1. Rules¶
1.1. Introduction¶
Exakat provides unique 1432 rules to detect BUGS, CODE SMELLS, SECURITY OR QUALITY ISSUES in your PHP code.
Each rule is documented with code example to allow you to remediate your code. If you want to automate remediation, ours cobblers can are there to fix the issues in your code for your.
1.2. List of Rules¶
1.2.1. Ambiguous Array Index¶
Indexes should not be defined with different types than int or string.
Array indices only accept integers and strings, so any other type of literal is reported. In fact, null is turned into an empty string, booleans are turned into an integer, and real numbers are truncated (not rounded).
<?php
$x = [ 1 => 1,
'1' => 2,
1.0 => 3,
true => 4];
// $x only contains one element : 1 => 4
// Still wrong, immediate typecast to 1
$x[1.0] = 5;
$x[true] = 6;
?>
They are indeed distinct, but may lead to confusion.
1.2.1.1. Suggestions¶
Only use string or integer as key for an array.
Use transtyping operator (string) and (int) to make sure of the type
See also and array.
1.2.1.2. Specs¶
Short name |
Arrays/AmbiguousKeys |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.2. Array() / [ ] Consistence¶
array() or [ ] is the favorite.
array() and [ ] have the same functional use.
The analyzed code has less than 10% of one of them : for consistency reasons, it is recommended to make them all the same.
It happens that array() or [] are used depending on coding style and files. One file may be consistently using array(), while the others are all using [].
<?php
$a = array(1, 2);
$b = array(array(3, 4), array(5, 6));
$c = array(array(array(7, 8), array(9, 10)), array(11, 12), array(13, 14)));
// be consistent
$d = [1, 3];
?>
The only drawback to use [] over array() is backward incompatibility.
1.2.2.1. Suggestions¶
Use one syntax consistently.
Name |
Default |
Type |
Description |
array_ratio |
10 |
integer |
Percentage of arrays in one of the syntaxes, to trigger the other syntax as a violation. |
See also and .
1.2.2.2. Specs¶
Short name |
Arrays/ArrayBracketConsistence |
Rulesets |
|
Exakat since |
0.8.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.3. Short Syntax For Arrays¶
Arrays written with the new short syntax.
PHP 5.4 introduced the new short syntax, with square brackets. The previous syntax, based on the array() keyword is still available.
<?php
// All PHP versions array
$a = array(1, 2, 3);
// PHP 5.4+ arrays
$a = [1, 2, 3];
?>
See also and Array.
1.2.3.1. Specs¶
Short name |
Arrays/ArrayNSUsage |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
With PHP 5.3 and more recent |
Severity |
Critical |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Available in |
1.2.4. Array Index¶
List of all indexes used in arrays.
<?php
// Index
$x['index'] = 1;
// in array creation
$a = array('index2' => 1);
$a2 = ['index3' => 2];
?>
1.2.4.1. Specs¶
Short name |
Arrays/Arrayindex |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
Very high |
Available in |
1.2.5. Empty Final Element¶
The array() construct allows for the empty last element.
By putting an element on each line, and adding the final comma, it is possible to reduce the size of the diff when comparing code with the previous version.
<?php
// Array definition with final empty element
$array = [1,
2,
3,
];
// This array definition has only one line of diff with the previous array : the line with '4,'
$array = [1,
2,
3,
4,
];
// This array definition is totally different from the first array :
$array = [1, 2, 3, 4];
?>
See also Array, Zend Framework Coding Standard and How clean is your code? How clean are your diffs?.
1.2.5.1. Specs¶
Short name |
Arrays/EmptyFinal |
Rulesets |
|
Exakat since |
0.11.0 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.6. Empty Slots In Arrays¶
PHP tolerates the last element of an array to be empty.
<?php
$a = array( 1, 2, 3, );
$b = [ 4, 5, ];
?>
1.2.6.1. Specs¶
Short name |
Arrays/EmptySlots |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.7. Getting Last Element¶
Getting the last element of an array relies on array_key_last().
array_key_last() was added in PHP 7.3. Before that,
<?php
$array = ['a' => 1, 'b' => 2, 'c' => 3];
// Best solutions, by far
$last = $array[array_key_last($array)];
// Best solutions, just as fast as each other
$last = $array[count($array) - 1];
$last = end($array);
// Bad solutions
// popping, but restoring the value.
$last = array_pop($array);
$array[] = $last;
// array_unshift would be even worse
// reversing array
$last = array_reverse($array)[0];
// slicing the array
$last = array_slice($array, -1)[0]',
$last = current(array_slice($array, -1));
);
?>
1.2.7.1. Suggestions¶
Use PHP native function : array_key_last(), when using PHP 7.4 and later
Use PHP native function : array_pop()
Organise the code to put the last element in the first position (array_unshift() instead of append operator [])
1.2.7.2. Specs¶
Short name |
Arrays/GettingLastElement |
Rulesets |
|
Exakat since |
0.9.0 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.8. Mass Creation Of Arrays¶
Literal creation of an array, by assigning a lot of index.
<?php
$row['name'] = $name;
$row['last'] = $last;
$row['address'] = $address;
?>
1.2.8.1. Specs¶
Short name |
Arrays/MassCreation |
Rulesets |
|
Exakat since |
1.1.8 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.9. Mistaken Concatenation¶
A unexpected structure is built for initialization. It may be a typo that creates an unwanted expression.
<?php
// This 'cd' is unexpected. Isn't it 'c', 'd' ?
$array = array('a', 'b', 'c'. 'd');
$array = array('a', 'b', 'c', 'd');
// This 4.5 is unexpected. Isn't it 4, 5 ?
$array = array(1, 2, 3, 4.5);
$array = array(1, 2, 3, 4, 5);
?>
1.2.9.1. Specs¶
Short name |
Arrays/MistakenConcatenation |
Rulesets |
|
Exakat since |
1.0.8 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.10. Mixed Keys Arrays¶
Avoid mixing constants and literals in array keys.
When defining default values in arrays, it is recommended to avoid mixing constants and literals, as PHP may mistake them and overwrite the previous with the latter.
Either switch to a newer version of PHP (5.5 or newer), or make sure the resulting array hold the expected data. If not, reorder the definitions.
<?php
const ONE = 1;
$a = [ 1 => 2,
ONE => 3];
?>
1.2.10.1. Suggestions¶
Use only literals or constants when building the array
1.2.10.2. Specs¶
Short name |
Arrays/MixedKeys |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
With PHP 5.6 and more recent |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.11. Multidimensional Arrays¶
Simply, arrays of arrays.
<?php
$x[1][2] = $x[2][3][4];
?>
See also Type array and Using Multidimensional Arrays in PHP.
1.2.11.1. Specs¶
Short name |
Arrays/Multidimensional |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.12. Multiple Index Definition¶
Indexes that are defined multiple times in the same array.
<?php
// Multiple identical keys
$x = array(1 => 2,
2 => 3,
1 => 3);
// Multiple identical keys (sneaky version)
$x = array(1 => 2,
1.1 => 3,
true => 4);
// Multiple identical keys (automated version)
$x = array(1 => 2,
3, // This will be index 2
2 => 4); // this index is overwritten
?>
They are indeed overwriting each other. This is most probably a typo.
1.2.12.1. Suggestions¶
Review your code and check that arrays only have keys defined once.
Review carefully your code and check indirect values, like constants, static constants.
1.2.12.2. Specs¶
Short name |
Arrays/MultipleIdenticalKeys |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
Very high |
Examples |
|
Available in |
1.2.13. Negative Start Index In Array¶
Negative starting index in arrays changed in PHP 8.0. Until then, they were ignored, and automatic index started always at 0. Since PHP 8.0, the next index is calculated.
The behavior will break code that relies on automatic index in arrays, when a negative index is used for a starter.
<?php
$x = [-5 => 2];
$x[] = 3;
print_r($x);
/*
PHP 7.4 and older
Array
(
[-5] => 2
[0] => 3
)
*/
/*
PHP 8.0 and more recent
Array
(
[-5] => 2
[-4] => 3
)
*/
?>
1.2.13.1. Suggestions¶
Explicitly create the index, instead of using the automatic indexing
Add an explicit index of 0 in the initial array, to set the automatic process in the right track
Avoid using specified index in array, conjointly with automatic indexing.
See also and PHP RFC: Arrays starting with a negative index.
1.2.13.2. Specs¶
Short name |
Arrays/NegativeStart |
Rulesets |
|
Exakat since |
2.1.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Available in |
1.2.14. No Spread For Hash¶
The spread operator
...only works on integer-indexed arrays.
<?php
// This is valid, as ``-33`` is cast to integer by PHP automagically
var_dump(...[1,-33 => 2, 3]);
// This is not valid
var_dump(...[1,C => 2, 3]);
?>
1.2.14.1. Suggestions¶
Add a call to array_values() instead of the hash
Upgrade to PHP 8.1
See also and Variable-length argument lists.
1.2.14.2. Specs¶
Short name |
Arrays/NoSpreadForHash |
Rulesets |
|
Exakat since |
1.9.3 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.15. Non-constant Index In Array¶
Undefined constants revert as strings in Arrays. They are also called
barewords.
In $array[index], PHP cannot find index as a constant, but, as a default behavior, turns it into the string index.
This default behavior raise concerns when a corresponding constant is defined, either using define() or the const keyword (outside a class). The definition of the index constant will modify the behavior of the index, as it will now use the constant definition, and not the ‘index’ string.
<?php
// assign 1 to the element index in $array
// index will fallback to string
$array[index] = 1;
//PHP Notice: Use of undefined constant index - assumed 'index'
echo $array[index]; // display 1 and the above error
echo "$array[index]"; // display 1
echo "$array['index']"; // Syntax error
define('index', 2);
// now 1 to the element 2 in $array
$array[index] = 1;
?>
It is recommended to make index a real string (with ‘ or “), or to define the corresponding constant to avoid any future surprise.
Note that PHP 7.2 removes the support for this feature.
See also PHP RFC: Deprecate and Remove Bareword (Unquoted) Strings and Syntax.
1.2.15.1. Suggestions¶
Declare the constant to give it an actual value
Turn the constant name into a string
1.2.15.2. Specs¶
Short name |
Arrays/NonConstantArray |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.16. Null Or Boolean Arrays¶
Null and booleans are valid PHP array base. Yet, they only produces
nullvalues. They also did not emits any warning until PHP 7.4.
This analysis has been upgraded to cover int and float types too.
<?php
// outputs NULL
var_dump(null[0]);
const MY_CONSTANT = true;
// outputs NULL
var_dump(MY_CONSTANT[10]);
?>
See also Null and True.
1.2.16.1. Suggestions¶
Avoid using the array syntax on null and boolean
Avoid using null and boolean on constant that are expecting arrays
1.2.16.2. Specs¶
Short name |
Arrays/NullBoolean |
Rulesets |
|
Exakat since |
1.8.6 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.17. PHP Arrays Index¶
List of indexes used when manipulating PHP arrays in the code.
<?php
// HTTP_HOST is a PHP array index.
$ip = 'http'.$_SERVER['HTTP_HOST'].'/'.$row['path'];
//'path' is not a PHP index
?>
1.2.17.1. Specs¶
Short name |
Arrays/Phparrayindex |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.18. Randomly Sorted Arrays¶
Those literal arrays are written in several places, but their items are in various orders.
This may reduce the reading and proofing of the arrays, and induce confusion. The random order may also be a residue of development : both arrays started with different values, but they grew overtime to handle the same items. The way they were written lead to the current order.
Unless order is important, it is recommended to always use the same order when defining literal arrays. This makes it easier to match different part of the code by recognizing one of its literal.
<?php
// an array
$set = [1,3,5,9,10];
function foo() {
// an array, with the same values but different order, in a different context
$list = [1,3,5,10,9,];
}
// an array, with the same order than the initial one
$inits = [1,3,5,9,10];
?>
1.2.18.1. Suggestions¶
Match the sorting order of the arrays. Choose any of them.
Configure a constant and use it as a replacement for those arrays.
Leave the arrays intact : the order may be important.
For hash arrays, consider turning the array in a class.
1.2.18.2. Specs¶
Short name |
Arrays/RandomlySortedLiterals |
Rulesets |
|
Exakat since |
0.11.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Examples |
|
Available in |
1.2.19. Preprocess Arrays¶
Using long list of assignations for initializing arrays is significantly slower than the declaring them as an array.
<?php
// Slow way
$a = []; // also with $a = array();
$a[1] = 2;
$a[2] = 3;
$a[3] = 5;
$a[4] = 7;
$a[5] = 11;
// Faster way
$a = [1 => 2,
2 => 3,
3 => 5,
4 => 7,
5 => 11];
// Even faster way if indexing is implicit
$a = [2, 3, 5, 7, 11];
?>
If the array has to be completed rather than created, it is also faster to use += when there are more than ten elements to add.
<?php
// Slow way
$a = []; // also with $a = array();
$a[1] = 2;
$a[2] = 3;
$a[3] = 5;
// some expressions to get $seven and $eleven
$a[4] = $seven;
$a[5] = $eleven;
// Faster way
$a = [1 => 2,
2 => 3,
3 => 5];
// some expressions to get $seven and $eleven
$a += [4 => $seven,
5 => $eleven];
// Even faster way if indexing is implicit
$a = [2, 3, 5];
// some expressions to get $seven and $eleven
$a += [$seven, $eleven];
?>
1.2.19.1. Suggestions¶
Preprocess the code so PHP doesn’t do it. Keep the detailed version into comments.
1.2.19.2. Specs¶
Short name |
Arrays/ShouldPreprocess |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.20. Slice Arrays First¶
Always start by reducing an array before applying some transformation on it. The shorter array will be processed faster.
<?php
// fast version
$a = array_map('foo', array_slice($array, 2, 5));
// slower version
$a = array_slice(array_map('foo', $array), 2, 5);
?>
The gain produced here is greater with longer arrays, or greater reductions. They may also be used in loops. This is a micro-optimisation when used on short arrays.
1.2.20.1. Suggestions¶
Use the array transforming function on the result of the array shortening function.
1.2.20.2. Specs¶
Short name |
Arrays/SliceFirst |
Rulesets |
|
Exakat since |
1.0.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.21. String Initialization¶
It used to be possible to initialize a variable with an string, and use it as an array. It is not the case anymore in PHP 7.1.
<?php
// Initialize arrays with array()
$a = array();
$a[3] = 4;
// Don't start with a string
$a = '';
$a[3] = 4;
print $a;
// Don't start with a string
if (is_numeric($a)) {
$a[] = $a;
}
?>
1.2.21.1. Suggestions¶
Always initialize arrays with an empty array(), not a string.
1.2.21.2. Specs¶
Short name |
Arrays/StringInitialization |
Rulesets |
|
Exakat since |
1.6.5 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.22. Too Many Array Dimensions¶
When arrays a getting to many nesting.
<?php
$a = array(); // level 1;
$a[1] = array(); // level 2
$a[1][2] = array(); // level 3 : still valid by default
$a[1][2][3] = array(); // level 4
?>
PHP has no limit, and accepts any number of nesting levels. Yet, this is usually very memory hungry.
Name |
Default |
Type |
Description |
maxDimensions |
3 |
integer |
Number of valid dimensions in an array. |
1.2.22.1. Specs¶
Short name |
Arrays/TooManyDimensions |
Rulesets |
|
Exakat since |
1.9.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.23. Weird Array Index¶
Array index that looks weird. Arrays index may be string or integer, but some strings looks weird.
In particular, strings that include terminal white spaces, often leads to missed values.
<?php
$array = ['a ' => 1, 'b' => 2, 'c' => 3];
// Later in the code
//Notice: Undefined index: a in /Users/famille/Desktop/analyzeG3/test.php on line 8
echo $array['a'];
//Notice: Undefined index: b in /Users/famille/Desktop/analyzeG3/test.php on line 10
// Note that the space is visible, but easy to miss
echo $array['b '];
// all fine here
echo $array['c'];
?>
Although this is rare error, and often easy to spot, it is also very hard to find when it strikes.
1.2.23.1. Suggestions¶
Remove white spaces when using strings as array index.
1.2.23.2. Specs¶
Short name |
Arrays/WeirdIndex |
Rulesets |
|
Exakat since |
1.9.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.24. Handle Arrays With Callback¶
Use functions like array_map().
<?php
// Handles arrays with callback
$uppercase = array_map('strtoupper', $source);
// Handles arrays with foreach
foreach($source as &$s) {
$s = uppercase($s);
}
?>
See also array_map.
1.2.24.1. Specs¶
Short name |
Arrays/WithCallback |
Rulesets |
|
Exakat since |
1.3.7 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.25. Missing Attribute Attribute¶
While not strictly required it is recommended to create an actual class for every attribute.
<?php
namespace Example;
use Attribute;
#[Attribute]
class MyAttribute
{
}
#Missing the above attribute
class MyOtherAttribute
{
}
?>
1.2.25.1. Suggestions¶
Add the Attribute attribute to those classes
See also and Declaring Attribute Classes.
1.2.25.2. Specs¶
Short name |
Attributes/MissingAttributeAttribute |
Rulesets |
|
Exakat since |
2.2.4 |
PHP Version |
With PHP 8.0 and more recent |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Available in |
1.2.26. Modify Immutable¶
A class, marked as immutable, is being modified.
This attribute is supported as a PHPdoc comment, `@immutable, and as a PHP 8.0 attribute.
<?php
/** @Immutable */
#[Immutable]
class x {
public $x = 1, $y, $z;
}
$x = new X;
// $x->x is modified, while it should not
$x->x = 2 + $x->z;
// $x->z is read only, as expected
?>
See also phpstorm-stubs/meta/attributes/Immutable.php and PhpStorm 2020.3 EAP #4: Custom PHP 8 Attributes.
1.2.26.1. Suggestions¶
Removed the modification
Clone the immutable object
1.2.26.2. Specs¶
Short name |
Attributes/ModifyImmutable |
Rulesets |
|
Exakat since |
2.2.0 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Medium |
Available in |
1.2.27. Abstract Or Implements¶
A class must implements all abstract methods of it parent, or be abstract too.
While PHP lints this code, it won’t execute it and stop with a Fatal Error : Class BA contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (A\:\:aFoo).
<?php
abstract class Foo {
abstract function FooBar();
}
// This is in another file : php -l would detect it right away
class FooFoo extends Foo {
// The method is not defined.
// The class must be abstract, just like Foo
}
?>
See also Class Abstraction.
1.2.27.1. Suggestions¶
Implements all the abstract methods of the class
Make the class abstract
1.2.27.2. Specs¶
Short name |
Classes/AbstractOrImplements |
Rulesets |
|
Exakat since |
1.3.3 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.28. Abstract Static Methods¶
Methods cannot be both abstract and static. Static methods belong to a class, and will not be overridden by the child class. For normal methods, PHP will start at the object level, then go up the hierarchy to find the method. With static, it is necessary to mention the name, or use Late Static Binding, with self or static. Hence, it is useless to have an abstract static method : it should be a static method.
A child class is able to declare a method with the same name than a static method in the parent, but those two methods will stay independent.
This is not the case anymore in PHP 7.0+.
<?php
abstract class foo {
// This is not possible
static abstract function bar() ;
}
?>
1.2.28.1. Suggestions¶
Remove abstract keyword from the method
Remove static keyword from the method
Remove the method
See also and Why does PHP 5.2+ disallow abstract static class methods?.
1.2.28.2. Specs¶
Short name |
Classes/AbstractStatic |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
7.0- |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Available in |
1.2.29. Abstract Class Usage¶
List of all abstract classes being used.
<?php
abstract class foo {
function foobar();
}
class bar extends foo {
// extended method
function foobar() {
// doSomething()
}
// extra method
function barbar() {
// doSomething()
}
}
?>
See also Classes abstraction.
1.2.29.1. Suggestions¶
1.2.29.2. Specs¶
Short name |
Classes/Abstractclass |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
Very high |
Available in |
1.2.30. Abstract Methods Usage¶
List of all abstract methods being used.
<?php
// abstract class
abstract class foo {
// abstract method
function foobar();
}
class bar extends foo {
// extended abstract method
function foobar() {
// doSomething()
}
// extra method
function barbar() {
// doSomething()
}
}
?>
See also Classes abstraction.
1.2.30.1. Specs¶
Short name |
Classes/Abstractmethods |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
Very high |
Available in |
1.2.31. Accessing Private¶
List of calls to private properties/methods that will compile but yield some fatal error upon execution.
<?php
class a {
private $a;
}
class b extends a {
function c() {
$this->a;
}
}
?>
1.2.31.1. Specs¶
Short name |
Classes/AccessPrivate |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.32. Access Protected Structures¶
It is not allowed to access protected properties, methods or constants from outside the class or its relatives.
<?php
class foo {
protected $bar = 1;
}
$foo = new Foo();
$foo->bar = 2;
?>
1.2.32.1. Suggestions¶
Change ‘protected’ to ‘public’ to relax the constraint
Add a getter method to reach the target value
Remove the access to the protected value and find it another way
See also Visibility. and Understanding The Concept Of Visibility In Object Oriented PHP.
1.2.32.2. Specs¶
Short name |
Classes/AccessProtected |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.33. Ambiguous Static¶
Try to keep the methods simple and unique. Consider renaming the methods and properties to distinguish them easily. A method and a static method have probably different responsibilities.
<?php
class a {
function mixedStaticMethod() {}
}
class b {
static function mixedStaticMethod() {}
}
/... a lot more code later .../
$c->mixedStaticMethod();
// or
$c::mixedStaticMethod();
?>
1.2.33.1. Specs¶
Short name |
Classes/AmbiguousStatic |
Rulesets |
|
Exakat since |
1.0.3 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.34. Ambiguous Visibilities¶
The properties have the same name, but have different visibilities, across different classes.
While it is legit to have a property with the same name in different classes, it may easily lead to confusion. As soon as the context is need to understand if the property is accessible or not, the readability suffers.
It is recommended to handle the same properties in the same way across classes, even when the classes are not related.
<?php
class person {
public $name;
private $address;
}
class gangster {
private $name;
public $nickname;
private $address;
}
$someone = Human::load(123);
echo 'Hello, '.$someone->name;
?>
1.2.34.1. Suggestions¶
Sync visibilities for both properties, in the different classes
Use different names for properties with different usages
1.2.34.2. Specs¶
Short name |
Classes/AmbiguousVisibilities |
Rulesets |
|
Exakat since |
1.3.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Examples |
|
Available in |
1.2.35. Anonymous Classes¶
Anonymous classes.
<?php
// Anonymous class, available since PHP 7.0
$object = new class { function __construct() { echo __METHOD__; } };
?>
1.2.35.1. Specs¶
Short name |
Classes/Anonymous |
Rulesets |
Appinfo, CE, CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, All |
Exakat since |
0.8.4 |
PHP Version |
7.0+ |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.36. Avoid option arrays in constructors¶
Avoid option arrays in constructors. Use one parameter per injected element.
<?php
class Foo {
// Distinct arguments, all typehinted if possible
function __constructor(A $a, B $b, C $c, D $d) {
$this->a = $a;
$this->b = $b;
$this->c = $c;
$this->d = $d;
}
}
class Bar {
// One argument, spread over several properties
function __constructor(array $options) {
$this->a = $options['a'];
$this->b = $options['b'];
$this->c = $options['c'];
$this->d = $options['d'];
}
}
?>
See also Avoid option arrays in constructors and PHP RFC: Named Arguments (Type-safe and documented options).
1.2.36.1. Suggestions¶
Spread the options in the argument list, one argument each
Use a configuration class, that hold all the elements with clear names, instead of an array
Use named parameters to pass and document the arguments
1.2.36.2. Specs¶
Short name |
Classes/AvoidOptionArrays |
Rulesets |
|
Exakat since |
1.7.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Medium |
Available in |
1.2.37. Avoid Optional Properties¶
Avoid optional properties, to prevent littering the code with existence checks.
When a property has to be checked once for existence, it is safer to check it each time. This leads to a decrease in readability and a lot of checks added to the code.
Either make sure the property is set with an actual object rather than with null, or use a null object. A null object offers the same interface than the expected object, but does nothing. It allows calling its methods, without running into a Fatal error, nor testing it.
<?php
// Example is courtesy 'The Coding Machine' : it has been adapted from its original form. See link below.
class MyMailer {
private $logger;
public function __construct(LoggerInterface $logger = null) {
$this->logger = $logger;
}
private function sendMail(Mail $mail) {
// Since $this->logger may be null, it must be tested anytime it is used.
if ($this->logger) {
$this->logger->info('Mail successfully sent.');
}
}
}
?>
See also Avoid optional services as much as possible, The Null Object Pattern – Polymorphism in Domain Models, and Practical PHP Refactoring: Introduce Null Object.
1.2.37.1. Suggestions¶
Use a null object to fill any missing value
Make sure the property is set at constructor time
1.2.37.2. Specs¶
Short name |
Classes/AvoidOptionalProperties |
Rulesets |
|
Exakat since |
0.12.0 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Examples |
|
Available in |
1.2.38. Custom Class Usage¶
List of usage of custom classes throughout the code.
Name |
Default |
Type |
Description |
forbiddenClasses |
ini_hash |
List of classes to be avoided |
1.2.38.1. Specs¶
Short name |
Classes/AvoidUsing |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.39. Cancel Common Method¶
A parent method’s is too little used in children.
The parent class has a method, which is customised in children classes, though most of the time, those are empty : hence, cancelled.
<?php
class x {
abstract function foo();
abstract function bar();
}
class y1 extends x {
function foo() { doSomething(); }
function bar() { doSomething(); };
}
class y2 extends x {
// foo is cancelled : it must be written, but has no use.
function foo() { }
function bar() { doSomething(); };
}
?>
A threshold of cancelThreshold % of the children methods have to be cancelled to report the parent class. By default, it is 75 (or 3 out of 4).
1.2.39.1. Suggestions¶
Drop the common method, and the cancelled methods in the children
Fill the children’s methods with actual code
Name |
Default |
Type |
Description |
cancelThreshold |
75 |
integer |
Minimal number of cancelled methods to suggest the cancellation of the parent. |
1.2.39.2. Specs¶
Short name |
Classes/CancelCommonMethod |
Rulesets |
|
Exakat since |
2.1.8 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.40. Can’t Extend Final¶
It is not possible to extend final classes.
Since PHP fails with a fatal error, this means that the extending class is probably not used in the rest of the code. Check for dead code.
<?php
// File Foo
final class foo {
public final function bar() {
// doSomething
}
}
?>
In a separate file :
<?php
// File Bar
class bar extends foo {
}
?>
See also Final Keyword.
1.2.40.1. Suggestions¶
Remove the final keyword
Remove the extending class
1.2.40.2. Specs¶
Short name |
Classes/CantExtendFinal |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Critical |
Time To Fix |
Instant (5 mins) |
Precision |
Medium |
Available in |
1.2.41. Cant Inherit Abstract Method¶
Inheriting abstract methods was made available in PHP 7.2. In previous versions, it emitted a fatal error.
<?php
abstract class A { abstract function bar(stdClass $x); }
abstract class B extends A { abstract function bar($x): stdClass; }
// Fatal error: Can't inherit abstract function A::bar()
?>
1.2.41.1. Suggestions¶
Avoid inheriting abstract methods for compatibility beyond 7.2 (and older)
See also and PHP RFC: Allow abstract function override.
1.2.41.2. Specs¶
Short name |
Classes/CantInheritAbstractMethod |
Rulesets |
CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, CompatibilityPHP70, CompatibilityPHP71, All |
Exakat since |
0.11.8 |
PHP Version |
With PHP 7.2 and more recent |
Severity |
Critical |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Available in |
1.2.42. Cant Instantiate Class¶
When constructor is not public, it is not possible to instantiate such a class. Either this is a conception choice, or there are factories to handle that. Either way, it is not possible to call new on such class.
PHP reports an error similar to this one : ‘Call to private Y::__construct() from invalid context’.
<?php
//This is the way to go
$x = X::factory();
//This is not possible
$x = new X();
class X {
//This is also the case with proctected __construct
private function __construct() {}
static public function factory() {
return new X();
}
}
?>
See also In a PHP5 class, when does a private constructor get called?, Named Constructors in PHP and PHP Constructor Best Practices And The Prototype Pattern.
1.2.42.1. Specs¶
Short name |
Classes/CantInstantiateClass |
Rulesets |
|
Exakat since |
1.2.8 |
PHP Version |
All |
Severity |
Critical |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.43. Check On __Call Usage¶
When using the magic methods __call() and __staticcall(), make sure the method exists before calling it.
If the method doesn’t exists, then the same method will be called again, leading to the same failure. Finally, it will crash PHP.
<?php
class safeCall {
function __class($name, $args) {
// unsafe call, no checks
if (method_exists($this, $name)) {
$this->$name(...$args);
}
}
}
class unsafeCall {
function __class($name, $args) {
// unsafe call, no checks
$this->$name(...$args);
}
}
?>
See also Method overloading and ``Magical PHP: __call <https://www.garfieldtech.com/index.php/blog/magical-php-call>`_.
1.2.43.1. Suggestions¶
Add a call to method_exists() before using any method name
Relay the call to another object that doesn’t handle __call() or __callStatic()
1.2.43.2. Specs¶
Short name |
Classes/CheckOnCallUsage |
Rulesets |
|
Exakat since |
1.7.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.44. Child Class Removes Typehint¶
PHP 7.2 introduced the ability to remove a typehint when overloading a method. This is not valid code for older versions.
<?php
class foo {
function foobar(foo $a) {}
}
class bar extends foo {
function foobar($a) {}
}
?>
1.2.44.1. Specs¶
Short name |
Classes/ChildRemoveTypehint |
Rulesets |
CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, CompatibilityPHP70, CompatibilityPHP71, Typechecks, All |
Exakat since |
0.12.4 |
PHP Version |
7.2+ |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.45. Class, Interface Or Trait With Identical Names¶
The following names are used at the same time for classes, interfaces or traits. For example,
<?php
class a { /* some definitions */ }
interface a { /* some definitions */ }
trait a { /* some definitions */ }
?>
Even if they are in different namespaces, identical names makes classes easy to confuse. This is often solved by using alias at import time : this leads to more confusion, as a class suddenly changes its name.
Internally, PHP use the same list for all classes, interfaces and traits. As such, it is not allowed to have both a trait and a class with the same name.
In PHP 4, and PHP 5 before namespaces, it was not possible to have classes with the same name. They were simply included after a check.
1.2.45.1. Suggestions¶
Use distinct names for every class, trait and interface.
Keep eponymous classes, traits and interfaces in distinct files, for definition but also for usage. When this happens, rename one of them.
1.2.45.2. Specs¶
Short name |
Classes/CitSameName |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.46. Usage Of class_alias()¶
class_aliascreates dynamically an alias for classes.
<?php
class foo { }
class_alias('foo', 'bar');
$a = new foo;
$b = new bar;
// the objects are the same
var_dump($a == $b, $a === $b);
var_dump($a instanceof $b);
// the classes are the same
var_dump($a instanceof foo);
var_dump($a instanceof bar);
var_dump($b instanceof foo);
var_dump($b instanceof bar);
?>
See also class_alias.
1.2.46.1. Specs¶
Short name |
Classes/ClassAliasUsage |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.47. Class Overreach¶
An object of class A may reach any private or protected properties or method in another object of the same class. This is a PHP feature, though seldom known.
s .. code-block:: php
<?php
- class A {
private $p = 1;
- public function foo(A $a) {
return $a->p + 1;
}
}
echo (new A)->foo(new A);
?>
See also Visibility from other objects.
1.2.47.1. Suggestions¶
Use a getter to reach inside the other object private properties
1.2.47.2. Specs¶
Short name |
Classes/ClassOverreach |
Rulesets |
|
Exakat since |
2.2.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
Medium |
Available in |
1.2.48. Class Usage¶
List of classes being used.
<?php
// Class may be used in a use expression
use MyClass as MyAliasedClass;
// class may be aliased with class_alias
class_alias('MyOtherAliasedClass', 'MyClass');
// Class may be instanciated
$o = new MyClass();
// Class may be used with instanceof
var_dump($o instanceof \MyClass);
// Class may be used in static calls
MyClass::aConstant;
echo MyClass::$aProperty;
echo MyClass::aMethod( $o );
// Class may be extended
class MyOtherClass {
}
class MyClass extends MyOtherClass {
const aConstant = 1;
public static $aProperty = 2;
// also used as a typehint
public static function aMethod(MyClass $object) {
return __METHOD__;
}
}
?>
1.2.48.1. Specs¶
Short name |
Classes/ClassUsage |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.49. Classes Names¶
List of all classes, as defined in the application.
<?php
// foo is in the list
class foo {}
// Anonymous classes are not in the list
$o = class { function foo(){} }
?>
1.2.49.1. Specs¶
Short name |
Classes/Classnames |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.50. Clone With Non-Object¶
The
clonekeyword must be used on variables, properties or results from a function or method call.
clone cannot be used with constants or literals.
<?php
class x { }
$x = new x();
// Valid clone
$y = clone $x;
// Invalid clone
$y = clone x;
?>
Cloning a non-object lint but won’t execute.
1.2.50.1. Suggestions¶
Only clone containers (like variables, properties…)
Add typehint to injected properties, so they are checked as objects.
See also and Object cloning.
1.2.50.2. Specs¶
Short name |
Classes/CloneWithNonObject |
Rulesets |
|
Exakat since |
1.7.0 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.51. Clone Usage¶
List of all clone situations.
<?php
$dateTime = new DateTime();
echo (clone $dateTime)->format('Y');
?>
See also Object cloning.
1.2.51.1. Specs¶
Short name |
Classes/CloningUsage |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.52. Const Visibility Usage¶
Visibility for class constant controls the accessibility to class constant.
A public constant may be used anywhere in the code; a protected constant usage is restricted to the class and its relatives; a private constant is restricted to itself.
This feature was introduced in PHP 7.1. It is recommended to use explicit visibility, and, whenever possible, make the visibility private.
<?php
class x {
public const a = 1;
protected const b = 2;
private const c = 3;
const d = 4;
}
interface i {
public const a = 1;
const d = 4;
}
?>
See also Class Constants and PHP RFC: Support Class Constant Visibility.
1.2.52.1. Suggestions¶
Add constant visibility, at least ‘public’.
1.2.52.2. Specs¶
Short name |
Classes/ConstVisibilityUsage |
Rulesets |
Appinfo, CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, CompatibilityPHP70, All |
Exakat since |
1.3.0 |
PHP Version |
7.1+ |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.53. Constant Class¶
A class or an interface only made up of constants. Constants usually have to be used in conjunction of some behavior (methods, class…) and never alone.
<?php
class ConstantClass {
const KBIT = 1000;
const MBIT = self::KBIT * 1000;
const GBIT = self::MBIT * 1000;
const PBIT = self::GBIT * 1000;
}
?>
As such, they should be PHP constants (build with define or const), or included in a class with other methods and properties.
See also PHP Classes containing only constants.
1.2.53.1. Suggestions¶
Make the class an interface
Make the class an abstract class, to avoid its instantiation
1.2.53.2. Specs¶
Short name |
Classes/ConstantClass |
Rulesets |
CE, ClassReview, All |
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.54. Constant Definition¶
List of class constants being defined.
<?php
// traditional way of making constants
define('aConstant', 1);
// modern way of making constants
const anotherConstant = 2;
class foo {
// Not a constant, a class constant.
const aClassConstant = 3;
}
?>
See also PHP Constants.
1.2.54.1. Specs¶
Short name |
Classes/ConstantDefinition |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.55. Constant Used Below¶
Mark class constants that are used in children classes.
<?php
class foo {
// This constant is used in children
protected PROTECTEDPROPERTY = 1;
// This constant is not used in children
protected LOCALPROTECTEDPROPERTY = 1;
private function foobar() {
// PROTECTEDPROPERTY is used here, but defined in parent
echo self::LOCALPROTECTEDPROPERTY;
}
}
class foofoo extends foo {
private function bar() {
// protectedProperty is used here, but defined in parent
print self::PROTECTEDPROPERTY;
}
}
?>
This analysis marks constants at their definition, not the current class, nor the (grand-)`parent <https://www.php.net/manual/en/language.oop5.paamayim-nekudotayim.php>`_.
1.2.55.1. Specs¶
Short name |
Classes/ConstantUsedBelow |
Rulesets |
|
Exakat since |
0.12.10 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.56. Constructors¶
Mark methods as constructors.
<?php
class x {
// Normal constructor
function __construct() {}
}
class y {
// Old style constructor, obsolete since PHP 7.1
function y() {}
}
class z {
// Normal constructor
function __construct() {}
// Old style constructor, but with lower priority
function z() {}
}
?>
See also Constructors and Destructors.
1.2.56.1. Specs¶
Short name |
Classes/Constructor |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.57. Could Be Abstract Class¶
An abstract class is never instantiated, and has children class that are. As such, a ‘parent’ class that is never instantiated by itself, but has its own children instantiated could be marked as abstract.
That will prevent new code to try to instantiate it.
<?php
// Example code would actually be split over multiple files.
// That class could be abstract
class motherClass {}
// Those classes shouldn't be abstract
class firstChildren extends motherClass {}
class secondChildren extends motherClass {}
class thirdChildren extends motherClass {}
new firstChildren();
new secondChildren();
new thirdChildren();
//Not a single : new motherClass()
?>
See also Class Abstraction Abstract classes and methods.
1.2.57.1. Suggestions¶
Make this class an abstract class
1.2.57.2. Specs¶
Short name |
Classes/CouldBeAbstractClass |
Rulesets |
|
Exakat since |
1.3.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.58. Could Be Class Constant¶
When a property is defined and read, but never modified, it may be a constant.
<?php
class foo {
// $this->bar is never modified.
private $bar = 1;
// $this->foofoo is modified, at least once
private $foofoo = 2;
function method($a) {
$this->foofoo = $this->bar + $a + $this->foofoo;
return $this->foofoo;
}
}
?>
Starting with PHP 5.6, even array() may be defined as constants.
1.2.58.1. Specs¶
Short name |
Classes/CouldBeClassConstant |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.59. Class Could Be Final¶
Any class that has no extension should be
finalby default.
As stated by Matthias Noback : If a class is not marked final, it has at least one subclass.
Prevent your classes from being subclassed by making them final. Sometimes, classes are not meant or thought to be derivable.
<?php
class x {} // This class is extended
class y extends x {} // This class is extended
class z extends y {} // This class is not extended
final class z2 extends y {} // This class is not extended
?>
1.2.59.1. Suggestions¶
Make the class final
Extends the class
See also and Negative architecture, and assumptions about code.
1.2.59.2. Specs¶
Short name |
Classes/CouldBeFinal |
Rulesets |
|
Exakat since |
1.4.3 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Available in |
1.2.60. Could Be Parent Method¶
<?php
// The parent class
class x { }
// The children class
class y1 extends x {
// foo is common to y1 and y2, so it shall be also a method in x
function foo() {}
// fooY1 is specific to y1
function fooY1() {}
}
class y2 extends x {
function foo() {}
// fooY2 is specific to y1
function fooY2() {}
}
?>
Only the name of the method is used is for gathering purposes. If the code has grown organically, the signature (default values, typehint, argument names) may have followed different path, and will require a refactorisation.
1.2.60.1. Suggestions¶
Create an abstract method in the parent
Create an concrete method in the parent, and move default behavior there by removing it in children classes
Name |
Default |
Type |
Description |
minChildren |
4 |
integer |
Minimal number of children using this method. |
1.2.60.2. Specs¶
Short name |
Classes/CouldBeParentMethod |
Rulesets |
|
Exakat since |
2.1.7 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.61. Property Could Be Private Property¶
The following properties are never used outside their class of definition Given the analyzed code, they could be set as private.
<?php
class foo {
public $couldBePrivate = 1;
public $cantdBePrivate = 1;
function bar() {
// couldBePrivate is used internally.
$this->couldBePrivate = 3;
}
}
class foo2 extends foo {
function bar2() {
// cantdBePrivate is used in a child class.
$this->cantdBePrivate = 3;
}
}
//$couldBePrivate is not used outside
$foo = new foo();
//$cantdBePrivate is used outside the class
$foo->cantdBePrivate = 2;
?>
Note that dynamic properties (such as $x->$y) are not taken into account.
1.2.61.1. Suggestions¶
Remove the unused property
Use the private property
Change the visibility to allow access the property from other part of the code
1.2.61.2. Specs¶
Short name |
Classes/CouldBePrivate |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.62. Could Be Private Class Constant¶
Class constant may use
privatevisibility.
Since PHP 7.1, constants may also have a public/protected/private visibility. This restrict their usage to anywhere, class and children or class.
As a general rule, it is recommended to make constant private by default, and to relax this restriction as needed. PHP makes them public by default.
<?php
class foo {
// pre-7.1 style
const PRE_71_CONSTANT = 1;
// post-7.1 style
private const PRIVATE_CONSTANT = 2;
public const PUBLIC_CONSTANT = 3;
function bar() {
// PRIVATE CONSTANT may only be used in its class
echo self::PRIVATE_CONSTANT;
}
}
// Other constants may be used anywhere
function x($a = foo::PUBLIC_CONSTANT) {
echo $a.' '.foo:PRE_71_CONSTANT;
}
?>
Constant shall stay public when the code has to be compatible with PHP 7.0 and older.
They also have to be public in the case of component : some of those constants have to be used by external actors, in order to configure the component.
See also Class Constants.
1.2.62.1. Specs¶
Short name |
Classes/CouldBePrivateConstante |
Rulesets |
|
Exakat since |
0.12.10 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.63. Method Could Be Private Method¶
The following methods are never used outside their class of definition. Given the analyzed code, they could be set as private.
<?php
class foo {
public function couldBePrivate() {}
public function cantdBePrivate() {}
function bar() {
// couldBePrivate is used internally.
$this->couldBePrivate();
}
}
class foo2 extends foo {
function bar2() {
// cantdBePrivate is used in a child class.
$this->cantdBePrivate();
}
}
//couldBePrivate() is not used outside
$foo = new foo();
//cantdBePrivate is used outside the class
$foo->cantdBePrivate();
?>
Note that dynamic properties (such as $x->$y) are not taken into account.
1.2.63.1. Specs¶
Short name |
Classes/CouldBePrivateMethod |
Rulesets |
|
Exakat since |
0.12.11 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.64. Could Be Protected Class Constant¶
Class constant may use ‘protected’ visibility.
Since PHP 7.1, constants may also have a public/protected/private visibility. This restrict their usage to anywhere, class and children or class.
As a general rule, it is recommended to make constant ‘private’ by default, and to relax this restriction as needed. PHP makes them public by default.
<?php
class foo {
// pre-7.1 style
const PRE_71_CONSTANT = 1;
// post-7.1 style
protected const PROTECTED_CONSTANT = 2;
public const PUBLIC_CONSTANT = 3;
}
class foo2 extends foo {
function bar() {
// PROTECTED_CONSTANT may only be used in its class or its children
echo self::PROTECTED_CONSTANT;
}
}
class foo3 extends foo {
function bar() {
// PROTECTED_CONSTANT may only be used in its class or any of its children
echo self::PROTECTED_CONSTANT;
}
}
// Other constants may be used anywhere
function x($a = foo::PUBLIC_CONSTANT) {
echo $a.' '.foo:PRE_71_CONSTANT;
}
?>
1.2.64.1. Specs¶
Short name |
Classes/CouldBeProtectedConstant |
Rulesets |
|
Exakat since |
0.12.11 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.65. Could Be Protected Method¶
Those methods are declared public, but are never used publicly. They may be made protected.
<?php
class foo {
// Public, and used publicly
public publicMethod() {}
// Public, but never used outside the class or its children
public protectedMethod() {}
private function bar() {
$this->protectedMethod();
}
}
$foo = new Foo();
$foo->publicMethod();
?>
These properties may even be made private.
1.2.65.1. Specs¶
Short name |
Classes/CouldBeProtectedMethod |
Rulesets |
|
Exakat since |
0.12.11 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.66. Could Be Protected Property¶
Those properties are declared public, but are never used publicly. They may be made protected.
<?php
class foo {
// Public, and used publicly
public $publicProperty;
// Public, but never used outside the class or its children
public $protectedProperty;
function bar() {
$this->protectedProperty = 1;
}
}
$foo = new Foo();
$foo->publicProperty = 3;
?>
This property may even be made private.
1.2.66.1. Specs¶
Short name |
Classes/CouldBeProtectedProperty |
Rulesets |
|
Exakat since |
0.9.7 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.67. Method Could Be Static¶
While static methods are usually harder to handle, recognizing the static status is a first step before turning the method into a standalone function.
<?php
class foo {
static $property = 1;
// legit static method
static function staticMethod() {
return self::$property;
}
// This is not using $this, and could be static
function nonStaticMethod() {
return self::$property;
}
// This is not using $this nor self, could be a standalone function
function nonStaticMethod() {
return self::$property;
}
}
?>
1.2.67.1. Suggestions¶
Make the method static
Make the method a standalone function
Make use of $this in the method : may be it was forgotten.
1.2.67.2. Specs¶
Short name |
Classes/CouldBeStatic |
Rulesets |
|
Exakat since |
1.5.7 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.68. Could Be Stringable¶
Stringable is an interface that mark classes as string-castable. It is introduced in PHP 8.0.
Classes that defined a __toString() magic method may be turned into a string when the typehint, argument, return or property, requires it. This is not the case when strict_types is activated. Yet, until PHP 8.0, there was nothing to identify a class as such.
<?php
// This class may implement Stringable
class x {
function __tostring() {
return 'asd';
}
}
echo (new x);
?>
1.2.68.1. Suggestions¶
Add implements stringable to the class definition
Add extends stringable to the interface definition
See also PHP RFC: Add Stringable interface and The Stringable interface.
1.2.68.2. Specs¶
Short name |
Classes/CouldBeStringable |
Rulesets |
|
Exakat since |
2.1.9 |
PHP Version |
With PHP 8.0 and more recent |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Available in |
1.2.69. Cyclic References¶
Avoid cyclic references.
Cyclic references happen when an object points to another object, which reciprocate. This is particularly possible with classes, when the child class has to keep a reference to the parent class.
<?php
class a {
private $p = null;
function foo() {
$this->p = new b();
// the current class is stored in the child class
$this->p->m($this);
}
}
class b {
private $pb = null;
function n($a) {
// the current class keeps a link to its parent
$this->pb = $a;
}
}
?>
Cyclic references, or circular references, are memory intensive : only the garbage collector can understand when they may be flushed from memory, which is a costly operation. On the other hand, in an acyclic reference code, the reference counter will know immediately know that an object is free or not.
See also About circular references in PHP and A Journey to find a memory leak.
1.2.69.1. Suggestions¶
Use a different object when calling the child objects.
Refactor your code to avoid the cyclic reference.
1.2.69.2. Specs¶
Short name |
Classes/CyclicReferences |
Rulesets |
|
Exakat since |
2.1.3 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.70. Defined Class Constants¶
Connect class constants with their definition when it can find it. This includes class constants, one level of parent (extended) or interfaces (implemented).
<?php
class X {
const Y = 2;
function foo() {
// This is defined on the line above
echo self::Y;
// This is not defined in the current code
echo X::X;
}
}
?>
1.2.70.1. Specs¶
Short name |
Classes/DefinedConstants |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.71. Defined Parent MP¶
<?php
class foo {
protected function parentDefined() {}
protected function unusedParentMethod() {}
// visibility is checked too
protected function unusuableParentMethod() {}
}
class bar extends foo {
private function someMethod() {
// reported
parent::parentDefined();
// not reported, as method is unreachable in parent
parent::unusuableParentMethod();
// not reported, as method is undefined in parent
parent::parentUndefined();
}
protected function parentDefined2() {}
}
?>
1.2.71.1. Specs¶
Short name |
Classes/DefinedParentMP |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.72. Defined Properties¶
List of properties that are explicitly defined in the class, its parents or traits.
<?php
class foo {
// property definition
private bar = 2;
}
?>
See also Properties.
1.2.72.1. Specs¶
Short name |
Classes/DefinedProperty |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.73. Defined static:: Or self::¶
<?php
class x {
static public function definedStatic() {}
private definedStatic = 1;
public function method() {
self::definedStatic();
self::undefinedStatic();
static::definedStatic;
static::undefinedStatic;
}
}
?>
1.2.73.1. Specs¶
Short name |
Classes/DefinedStaticMP |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.74. Law of Demeter¶
The law of Demeter specifies a number of constraints to apply to methodcalls from within an method, so as to keep dependencies to a minimum.
<?php
class x {
function foo($arg) {
$this->foo(); // calling oneself is OK
$this->x->bar(); // calling one's property is OK
$arg->bar2(); // calling arg's methods is OK
$local = new y();
$z = $y->bar3(); // calling a local variable is OK
$z->bar4(); // calling a method on a previous result is wrong
}
}
?>
See also Do your objects talk to strangers? and Law of Demeter.
1.2.74.1. Specs¶
Short name |
Classes/DemeterLaw |
Rulesets |
|
Exakat since |
1.6.7 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.75. Dependant Abstract Classes¶
Abstract classes should be autonomous. It is recommended to avoid depending on methods, constant or properties that should be made available in inheriting classes, without explicitly abstracting them.
The following abstract classes make usage of constant, methods and properties, static or not, that are not defined in the class. This means the inheriting classes must provide those constants, methods and properties, but there is no way to enforce this.
This may also lead to dead code : when the abstract class is removed, the host class have unused properties and methods.
<?php
// autonomous abstract class : all it needs is within the class
abstract class c {
private $p = 0;
function foo() {
return ++$this->p;
}
}
// dependant abstract class : the inheriting classes needs to provide some properties or methods
abstract class c2 {
function foo() {
// $p must be provided by the extending class
return ++$this->p;
}
}
class c3 extends c2 {
private $p = 0;
}
?>
See also Dependant Trait.
1.2.75.1. Suggestions¶
Make the class only use its own resources
Split the class in autonomous classes
Add local property definitions to make the class independent
1.2.75.2. Specs¶
Short name |
Classes/DependantAbstractClass |
Rulesets |
|
Exakat since |
1.8.6 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.76. Different Argument Counts¶
Two methods with the same name shall have the same number of compulsory argument. PHP accepts different number of arguments between two methods, if the extra arguments have default values. Basically, they shall be called interchangeably with the same number of arguments.
The number of compulsory arguments is often mistaken for the same number of arguments. When this is the case, it leads to confusion between the two signatures. It will also create more difficulties when refactoring the signature.
While this code is legit, it is recommended to check if the two signatures could be synchronized, and reduce future surprises.
<?php
class x {
function foo($a ) {}
}
class y extends x {
// This method is compatible with the above, its signature is different
function foo($a, $b = 1) {}
}
?>
1.2.76.1. Suggestions¶
Extract the extra arguments into other methods
Remove the extra arguments
Add the extra arguments to all the signatures
1.2.76.2. Specs¶
Short name |
Classes/DifferentArgumentCounts |
Rulesets |
|
Exakat since |
2.1.6 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.77. No Direct Call To Magic Method¶
PHP features magic methods, which are methods related to operators.
Magic methods, such as __get(), related to =, or __clone(), related to clone, are supposed to be used in an object environment, and not with direct call.
It is recommended to use the magic method with its intended usage, and not to call it directly. For example, typecast to string instead of calling the __toString() method.
<?php
// Write
print $x->a;
// instead of
print $x->__get('a');
class Foo {
private $b = secret;
public function __toString() {
return strtoupper($this->b);
}
}
$bar = new Foo();
echo (string) $bar;
?>
Accessing those methods in a static way is also discouraged.
See also Magic Methods and Magical PHP: `__call <https://www.garfieldtech.com/blog/magical-php-call>`_.
1.2.77.1. Specs¶
Short name |
Classes/DirectCallToMagicMethod |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.78. Disconnected Classes¶
One class is extending the other, but they do not use any features from one another. Basically, those two classes are using extends, but they are completely independent and may be separated.
When using the ‘extends’ keyword, the newly created classes are now acting together and making one. This should be visible in calls from one class to the other, or simply by property usage : they can’t live without each other.
On the other hand, two completely independent classes that are merged, although they should be kept separated.
<?php
class A {
private $pa = 1;
function fooA() {
$this->pa = 2;
}
}
// class B and Class A are totally independent
class B extends A {
private $pb = 1;
function fooB() {
$this->pb = 2;
}
}
// class C makes use of class A : it is dependent on the parent class
class C extends A {
private $pc = 1;
function fooB() {
$this->pc = 2 + $this->fooA();
}
}
?>
1.2.78.1. Suggestions¶
Remove the extension
Make actual usage of the classes, at least from one of them
See also and .
1.2.78.2. Specs¶
Short name |
Classes/DisconnectedClasses |
Rulesets |
|
Exakat since |
1.8.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Examples |
|
Available in |
1.2.79. Don’t Send $this In Constructor¶
Don’t use
$thisas an argument while in the __construct(). Until the constructor is finished, the object is not finished, and may be in an unstable state. Providing it to another code may lead to error.
This is true when the receiving structure puts the incoming object immediately to work, and don’t store it for later use.
<?php
// $this is only provided when Foo is constructed
class Foo {
private $bar = null;
private $data = array();
static public function build($data) {
$foo = new Foo($data);
// Can't build in one call. Must make it separate.
$foo->finalize();
}
private function __construct($data) {
// $this is provided too early
$this->data = $data;
}
function finalize() {
$this->bar = new Bar($this);
}
}
// $this is provided too early, leading to error in Bar
class Foo2 extends Foo {
private $bar = null;
private $data = array();
function __construct($data) {
// $this is provided too early
$this->bar = new Bar($this);
$this->data = $data;
}
}
class Bar {
function __construct(Foo $foo) {
// the cache is now initialized with a wrong
$this->cache = $foo->getIt();
}
}
?>
See also Don’t pass this out of a constructor.
1.2.79.1. Suggestions¶
Finish the constructor first, then call an external object.
Sending $this should be made accessible in a separate method, so external objects may call it.
Sending the current may be the responsibility of the method creating the object.
1.2.79.2. Specs¶
Short name |
Classes/DontSendThisInConstructor |
Rulesets |
|
Exakat since |
1.0.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Examples |
|
Available in |
1.2.80. Don’t Unset Properties¶
Avoid unsetting properties. They would go undefined, and raise more warnings.
When getting rid of a property, assign it to null. This keeps the property in the object, yet allows existence check without errors.
<?php
class Foo {
public $a = 1;
}
$a = new Foo();
var_dump((array) $a) ;
// la propriété est reportée, et null
// ['a' => null]
unset($a->a);
var_dump((array) $a) ;
//Empty []
// Check if a property exists
var_dump($a->b === null);
// Same result as above, but with a warning
var_dump($a->c === null);
?>
This analysis works on properties and static properties. It also reports magic properties being unset.
Thanks for Benoit Burnichon for the original idea.
1.2.80.1. Suggestions¶
Never unset properties : set it to null or its default value instead
Make the property an array, and set/unset its index
1.2.80.2. Specs¶
Short name |
Classes/DontUnsetProperties |
Rulesets |
|
Exakat since |
1.2.3 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Examples |
|
Available in |
1.2.81. Dynamic Classes¶
Dynamic calls of classes.
<?php
class x {
static function staticMethod() {}
}
$class = 'x';
$class::staticMethod();
?>
See also and .
1.2.81.1. Specs¶
Short name |
Classes/DynamicClass |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.82. Dynamic Class Constant¶
Dynamic calls to class constants.
Constant may be dynamically called with the constant() function.
<?php
// Dynamic access to 'E_ALL'
echo constant('E_ALL');
interface i {
const MY_CONSTANT = 1;
}
// Dynamic access to 'E_ALL'
echo constant('i::MY_CONSTANT');
?>
1.2.82.1. Specs¶
Short name |
Classes/DynamicConstantCall |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.83. Dynamic Methodcall¶
Dynamic calls to class methods.
<?php
class x {
static public function foo() {}
public function bar() {}
}
$staticmethod = 'foo';
// dynamic static method call to x::foo()
x::$staticmethod();
$method = 'bar';
// dynamic method call to bar()
$object = new x();
$object->$method();
?>
See also and .
1.2.83.1. Specs¶
Short name |
Classes/DynamicMethodCall |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.84. Dynamic New¶
Dynamic instantiation of classes.
<?php
$object = new $classname()
?>
.
1.2.84.1. Specs¶
Short name |
Classes/DynamicNew |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.85. Dynamic Property¶
Dynamic access to class property.
<?php
class x {
static public $foo = 1;
public $bar = 2;
}
$staticproperty = 'foo';
// dynamic static property call to x::$foo
echo x::${$staticproperty};
$property = 'bar';
// dynamic property call to bar()
$object = new x();
$object->$property = 4;
?>
1.2.85.1. Specs¶
Short name |
Classes/DynamicPropertyCall |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.86. Dynamic Self Calls¶
A class that calls itself dynamically. This may be property or methods.
Calling itself dynamically happens when a class is configured to call various properties (container) or methods.
<?php
class x {
function foo() {
$f = 'goo';
return $this->$f();
}
function goo() {
return rand(1, 10);
}
}
?>
This rule is mostly useful internally, to side some special situations.
1.2.86.1. Specs¶
Short name |
Classes/DynamicSelfCalls |
Rulesets |
|
Exakat since |
2.1.1 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.87. Empty Classes¶
Classes that do no define anything at all. This is probably dead code.
Classes that are directly derived from an exception are omitted.
<?php
//Empty class
class foo extends bar {}
//Not an empty class
class foo2 extends bar {
const FOO = 2;
}
//Not an empty class, as derived from Exception
class barException extends \Exception {}
?>
1.2.87.1. Suggestions¶
Remove an empty class :it is probably dead code.
Add some code to the class to make it concrete.
1.2.87.2. Specs¶
Short name |
Classes/EmptyClass |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.88. Class Should Be Final By Ocramius¶
‘Make your classes always final, if they implement an interface, and no other public methods are defined’.
When a class should be final, as explained by Ocramius (Marco Pivetta).
<?php
interface i1 {
function i1() ;
}
// Class should final, as its public methods are in an interface
class finalClass implements i1 {
// public interface
function i1 () {}
// private method
private function a1 () {}
}
?>
See also When to declare classes final.
1.2.88.1. Specs¶
Short name |
Classes/FinalByOcramius |
Rulesets |
|
Exakat since |
0.9.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.89. Final Private Methods¶
PHP’s private methods cannot be overwritten, as they are dedicated to the current class. That way, the
finalkeyword is useless.
PHP 8.0 warns when it finds such a method.
<?php
class foo {
// Final and private both prevent child classes to overwrite the method
final private function bar() {}
// Final and protected (or public) keep this method available, but not overwritable
final protected function bar() {}
}
?>
1.2.89.2. Specs¶
Short name |
Classes/FinalPrivate |
Rulesets |
|
Exakat since |
2.2.0 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Available in |
1.2.90. Final Class Usage¶
List of all final classes being used.
final may be applied to classes and methods.
<?php
class BaseClass {
public function test() {
echo 'BaseClass::test() called'.PHP_EOL;
}
final public function moreTesting() {
echo 'BaseClass::moreTesting() called'.PHP_EOL;
}
}
class ChildClass extends BaseClass {
public function moreTesting() {
echo 'ChildClass::moreTesting() called'.PHP_EOL;
}
}
// Results in Fatal error: Cannot override final method BaseClass::moreTesting()
?>
See also Final Keyword.
1.2.90.1. Specs¶
Short name |
Classes/Finalclass |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.91. Final Methods Usage¶
List of all final methods being used.
final may be applied to classes and methods.
<?php
class BaseClass {
public function test() {
echo 'BaseClass::test() called'.PHP_EOL;
}
final public function moreTesting() {
echo 'BaseClass::moreTesting() called'.PHP_EOL;
}
}
class ChildClass extends BaseClass {
public function moreTesting() {
echo 'ChildClass::moreTesting() called'.PHP_EOL;
}
}
// Results in Fatal error: Cannot override final method BaseClass::moreTesting()
?>
See also Final Keyword.
1.2.91.1. Specs¶
Short name |
Classes/Finalmethod |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.92. Fossilized Method¶
A method is fossilized when it is overwritten so often that changing a default value, a return type or an argument type is getting difficult.
This happens when a class is extended. When a method is overwritten once, it may be easy to update the signature in two places. The more methods are overwriting a parent method, the more difficult it is to update it.
This analysis counts the number of times a method is overwritten, and report any method that is overwritten more than 6 times. This threshold may be configured.
<?php
class x1 {
// foo1() is never overwritten. It is easy to update.
function foo1() {}
// foo7() is overwritten seven times. It is hard to update.
function foo7() {}
}
// classes x2 to x7, all overwrite foo7();
// Only x2 is presente here.
class x2 extends x1 {
function foo7() {}
}
?>
Name |
Default |
Type |
Description |
fossilizationThreshold |
6 |
integer |
Minimal number of overwriting methods to consider a method difficult to update. |
1.2.92.1. Specs¶
Short name |
Classes/FossilizedMethod |
Rulesets |
|
Exakat since |
2.0.6 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.93. Class Has Fluent Interface¶
Mark a class as such when it contains at least one fluent method. A fluent method is a method that returns $this, for chaining.
<?php
class foo {
private $count = 0;
function a() {
++$this->count;
return $this;
}
function b() {
$this->count += 2;
return $this;
}
function c() {
return $this->count;
}
}
$bar = new foo();
print $bar->a()
->b()
->c();
// display 3 (1 + 2).
?>
1.2.93.1. Specs¶
Short name |
Classes/HasFluentInterface |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.94. Has Magic Method¶
The class has defined one of the magic methods.
The magic methods are : __call(), __callStatic(), __get(), __set(), __isset(), __unset(), __sleep(), __wakeup(), __toString(), __invoke(), __set_state(), __clone() and __debugInfo().
__construct() and __destruct() are omitted here.
<?php
class WithMagic {
// some more methods, const or properties
public function __get() {
// doSomething();
}
}
?>
See also and Property overloading..
1.2.94.1. Specs¶
Short name |
Classes/HasMagicProperty |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.96. Identical Methods¶
When the parent class and the child class have the same method, the child might drop it. This reduces code duplication.
Duplicate code in methods is often the results of code evolution, where a method was copied with the hierarchy, but the original wasn’t removed.
This doesn’t apply to private methods, which are reserved for one class.
<?php
class a {
public function foo() {
return rand(0, 100);
}
}
class b extends a {
public function foo() {
return rand(0, 100);
}
}
?>
1.2.96.1. Suggestions¶
Drop the method from the parent class, in particular if only one child uses the method.
Drop the method from the child class, in particular if there are several children class
Use an abstract method, and make sure every child has its own implementation
Modify one of the methods so they are different
1.2.96.2. Specs¶
Short name |
Classes/IdenticalMethods |
Rulesets |
|
Exakat since |
1.8.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Medium |
Available in |
1.2.97. Immutable Signature¶
Overwrites makes refactoring a method signature difficult. PHP enforces compatible signature, by checking if arguments have the same type, reference and default values.
In PHP 7.3, typehint had to be the same, or dropped. In PHP 7.4, typehint may be contravariant (arguments), or covariant (returntype).
This analysis may be configured with maxOverwrite. By default, a minimum of 8 overwritten methods is considered difficult to update.
<?php
// Changing any of the four foo() method signature will trigger a PHP warning
class a {
function foo($a) {}
}
class ab1 extends a {
// four foo() methods have to be refactored at the same time!
function foo($ab1) {}
}
class ab2 extends a {
function foo($ab2) {}
}
class ab3 extends ab1 {
function foo($abc1) {}
}
?>
When refactoring a method, all the related methodcall may have to be updated too. Adding a type, a default value, or a new argument with default value won’t affect the calls, but only the definitions. Otherwise, calls will also have to be updated.
IDE may help with signature refactoring, such as Refactoring code.
See also Covariance and contravariance (computer science), extends.
Name |
Default |
Type |
Description |
maxOverwrite |
8 |
integer |
Minimal number of method overwrite to consider that any refactor on the method signature is now hard. |
1.2.97.1. Specs¶
Short name |
Classes/ImmutableSignature |
Rulesets |
|
Exakat since |
1.9.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.98. Implement Is For Interface¶
With class heritage, implements should be used for interfaces, and extends with classes.
PHP defers the implements check until execution : the code in example does lint, but won,t run.
<?php
class x {
function foo() {}
}
interface y {
function foo();
}
// Use implements with an interface
class z implements y {}
// Implements is for an interface, not a class
class z implements x {}
?>
1.2.98.1. Suggestions¶
Create an interface from the class, and use it with the implements keyword
1.2.98.2. Specs¶
Short name |
Classes/ImplementIsForInterface |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.99. Implemented Methods Are Public¶
Class methods that are defined in an interface must be public. They cannot be either private, nor protected.
This error is not reported by lint, but is reported at execution time.
<?php
interface i {
function foo();
}
class X {
// This method is defined in the interface : it must be public
protected function foo() {}
// other methods may be private
private function bar() {}
}
?>
See also Interfaces and Interfaces - the next level of abstraction.
1.2.99.1. Suggestions¶
Make the implemented method public
1.2.99.2. Specs¶
Short name |
Classes/ImplementedMethodsArePublic |
Rulesets |
|
Exakat since |
0.11.5 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.100. Incompatible Signature Methods¶
Methods should have the same signature when being overwritten.
The same signatures means the children class must have :
the same name
the same visibility or less restrictive
the same typehint or removed
the same default value or removed
a reference like its parent
This problem emits a fatal error, for abstract methods, or a warning error, for normal methods. Yet, it is difficult to lint, because classes are often stored in different files. As such, PHP do lint each file independently, as unknown parent classes are not checked if not present. Yet, when executing the code, PHP lint the actual code and may encounter a fatal error.
<?php
class a {
public function foo($a = 1) {}
}
class ab extends a {
// foo is overloaded and now includes a default value for $a
public function foo($a) {}
}
?>
See also Object Inheritance.
1.2.100.1. Suggestions¶
Make signatures compatible again
1.2.100.2. Specs¶
Short name |
Classes/IncompatibleSignature |
Rulesets |
|
Exakat since |
1.3.3 |
PHP Version |
7.4- |
Severity |
Critical |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.101. Incompatible Signature Methods With Covariance¶
Methods should have the compatible signature when being overwritten.
The same signatures means the children class must have :
the same name
the same visibility or less restrictive
the same contravariant typehint or removed
the same covariant return typehint or removed
the same default value or removed
a reference like its parent
This problem emits a fatal error, for abstract methods, or a warning error, for normal methods. Yet, it is difficult to lint, because classes are often stored in different files. As such, PHP do lint each file independently, as unknown parent classes are not checked if not present. Yet, when executing the code, PHP lint the actual code and may encounter a fatal error.
<?php
class a {
public function foo($a = 1) {}
}
class ab extends a {
// foo is overloaded and now includes a default value for $a
public function foo($a) {}
}
?>
1.2.101.1. Suggestions¶
Make signatures compatible again
See also Object Inheritance, PHP RFC: Covariant Returns and Contravariant Parameters and Classes/IncompatibleSignature.
1.2.101.2. Specs¶
Short name |
Classes/IncompatibleSignature74 |
Rulesets |
|
Exakat since |
1.3.3 |
PHP Version |
7.4+ |
Severity |
Critical |
Time To Fix |
Quick (30 mins) |
Precision |
Medium |
Examples |
|
Available in |
1.2.102. Inherited Property Type Must Match¶
Properties that are inherited between classes must match.
This affect public and protected properties. Private properties are immune to this rule, as they actually are distinct properties.
<?php
class A {
private A $a;
protected array $b;
public $c;
}
class B extends A {
private A $a; // OK, as it is private
protected int $b; // type must match with the previous definition
public $c; // no type behaves just like a type : it must match too.
}
?>
See also ~`Properties <https://www.php.net/manual/en/language.oop5.properties.php>`_.
1.2.102.1. Suggestions¶
Remove the definition in the child class
Synch the definition of the property in the child class
1.2.102.2. Specs¶
Short name |
Classes/InheritedPropertyMustMatch |
Rulesets |
|
Exakat since |
2.2.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.103. Instantiating Abstract Class¶
PHP cannot instantiate an abstract class.
The classes are actually abstract classes, and should be derived into a concrete class to be instantiated.
<?php
abstract class Foo {
protected $a;
}
class Bar extends Foo {
protected $b;
}
// instantiating a concrete class.
new Bar();
// instantiating an abstract class.
// In real life, this is not possible also because the definition and the instantiation are in the same file
new Foo();
?>
See also Class Abstraction.
1.2.103.1. Specs¶
Short name |
Classes/InstantiatingAbstractClass |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.104. Insufficient Property Typehint¶
The typehint used for a class property doesn’t cover all it usage.
The typehint is insufficient when a undefined method is called, or if members are access while the typehint is an interface.
<?php
class A {
function a1() {}
}
// PHP 7.4 and more recent
class B {
private A $a = null;
function b2() {
// this method is available in A
$this->a->a1();
// this method is NOT available in A
$this->a->a2();
}
}
// Supported by all PHP versions
class C {
private $a = null;
function __construct(A $a) {
$this->a = $a;
}
function b2() {
// this method is available in A
$this->a->a1();
// this method is NOT available in A
$this->a->a2();
}
}
?>
This analysis relies on typehinted properties, as introduced in PHP 7.4. It also relies on typehinted assignations at construct time : the typehint of the assigned argument will be used as the property typehint. Getters and setters are not considered here.
1.2.104.1. Suggestions¶
Change the typehint to match the actual usage of the object in the class.
1.2.104.2. Specs¶
Short name |
Classes/InsufficientPropertyTypehint |
Rulesets |
|
Exakat since |
2.0.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.105. Integer As Property¶
It is backward incompatible to use integers are property names. This feature was introduced in PHP 7.2.
If the code must be compatible with previous versions, avoid casting arrays to object.
<?php
// array to object
$arr = [0 => 1];
$obj = (object) $arr;
var_dump(
$obj,
$obj->{'0'}, // PHP 7.2+ accessible
$obj->{0} // PHP 7.2+ accessible
$obj->{'b'}, // always been accessible
);
?>
See also PHP RFC: Convert numeric keys in object/array casts.
1.2.105.1. Specs¶
Short name |
Classes/IntegerAsProperty |
Rulesets |
CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, CompatibilityPHP70, CompatibilityPHP71, All |
Exakat since |
1.0.4 |
PHP Version |
7.2+ |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.106. Is An Extension Class¶
Those classes belongs to a PHP Extensions.
<?php
// This is a native PHP class
$o = new Stdclass();
// This is not a native PHP class
$o = new Elephpant();
?>
1.2.106.1. Specs¶
Short name |
Classes/IsExtClass |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.107. Is Interface Method¶
Mark a method as part of an interface that the current class implements.
<?php
interface i {
function i20();
}
class x implements i {
// This is an interface method
function i20() {}
// This is not an interface method
function x20() {}
}
?>
1.2.107.1. Specs¶
Short name |
Classes/IsInterfaceMethod |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.108. Is Not Class Family¶
Mark a static method call as inside the family of classes. Children are not considered here.
<?php
class a {
function familyMethod() {}
}
classs b {
function foo() {
self::familyMethod(); // This is a call to a family method
b::notAFamilyMethod(); // This is a call to a method of a class outside the family
}
}
?>
1.2.108.1. Specs¶
Short name |
Classes/IsNotFamily |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.109. Is Upper Family¶
Does the static call is made within the current hierarchy of class, or, is it made in the class, in the children or outside.
This applies to static methodcalls, property accesses and class constants.
<?php
class AAA { function inAAA() {} } // upper family : grand-parent
class AA extends AAA { function inAA() {} } // upper family : parent
class A extends AA { function inA() {} } // current family
class B extends A { function inB() {} } // lower family
class C { function inC() {} } // outside family
?>
1.2.109.1. Specs¶
Short name |
Classes/IsUpperFamily |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.110. Is A PHP Magic Property¶
Mark properties usage when they are actually a magic call.
<?php
class magicProperty {
public $b;
function __get($name) {
// do something with the value
}
function foo() {
$this->a;
$this->b;
}
}
?>
See also Magic Methods.
1.2.110.1. Specs¶
Short name |
Classes/IsaMagicProperty |
Rulesets |
|
Exakat since |
0.12.17 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.111. Locally Unused Property¶
Those properties are defined in a class, and this class doesn’t have any method that makes use of them.
While this is syntactically correct, it is unusual that defined resources are used in a child class. It may be worth moving the definition to another class, or to move accessing methods to the class.
<?php
class foo {
public $unused, $used;// property $unused is never used in this class
function bar() {
$this->used++; // property $used is used in this method
}
}
class foofoo extends foo {
function bar() {
$this->unused++; // property $unused is used in this method, but defined in the parent class
}
}
?>
1.2.111.1. Suggestions¶
Move the property definition to the child classes
Move some of the child method, using the property, to the parent class
1.2.111.2. Specs¶
Short name |
Classes/LocallyUnusedProperty |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.112. Locally Used Property¶
Properties that are used in the class where they are defined.
<?php
class foo {
public $unused, $used;// property $unused is never used in this class
function bar() {
$this->used++; // property $used is used in this method
}
}
$foo = new Foo();
$foo->unused = 'here'; // property $unused is used outside the class definition
?>
1.2.112.1. Specs¶
Short name |
Classes/LocallyUsedProperty |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.113. Magic Methods¶
List of PHP magic methods being used. The magic methods are
__call(), __callStatic(), __get(), __set(), __isset(), __unset(), __sleep(), __wakeup(), __toString(), __invoke(), __set_state(), __clone() and __debugInfo().
__construct and __destruct are omitted here, as they are routinely used to create and destroy objects.
<?php
class foo{
// PHP Magic method, called when cloning an object.
function __clone() {}
}
?>
See also Magic Method.
1.2.113.1. Specs¶
Short name |
Classes/MagicMethod |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.114. Magic Properties¶
List of magic properties used in the code
1.2.114.1. Specs¶
Short name |
Classes/MagicProperties |
Rulesets |
|
Exakat since |
1.9.5 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.115. Assign Default To Properties¶
Properties may be assigned default values at declaration time. Such values may be later modified, if needed.
<?php
class foo {
private $propertyWithDefault = 1;
private $propertyWithoutDefault;
private $propertyThatCantHaveDefault;
public function __construct() {
// Skip this extra line, and give the default value above
$this->propertyWithoutDefault = 1;
// Static expressions are available to set up simple computation at definition time.
$this->propertyWithoutDefault = OtherClass::CONSTANT + 1;
// Arrays, just like scalars, may be set at definition time
$this->propertyWithoutDefault = [1,2,3];
// Objects or resources can't be made default. That is OK.
$this->propertyThatCantHaveDefault = fopen('/path/to/file.txt');
$this->propertyThatCantHaveDefault = new Fileinfo();
}
}
?>
Default values will save some instructions in the constructor, and makes the value obvious in the code.
1.2.115.1. Suggestions¶
Add a default value whenever possible. This is easy for scalars, and array()
1.2.115.2. Specs¶
Short name |
Classes/MakeDefault |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
ClearPHP |
|
Examples |
|
Available in |
1.2.116. Make Global A Property¶
Calling global (or $GLOBALS) in methods is slower and less testable than setting the global to a property, and using this property.
Using properties is slightly faster than calling global or $GLOBALS, though the gain is not important.
Setting the property in the constructor (or in a factory), makes the class easier to test, as there is now a single point of configuration.
<?php
// Wrong way
class fooBad {
function x() {
global $a;
$a->do();
// Or $GLOBALS['a']->do();
}
}
class fooGood {
private $bar = null;
function __construct() {
global $bar;
$this->bar = $bar;
// Even better, do this via arguments
}
function x() {
$this->a->do();
}
}
?>
1.2.116.1. Suggestions¶
Avoid using global variables, and use properties instead
Remove the usage of these global variables
1.2.116.2. Specs¶
Short name |
Classes/MakeGlobalAProperty |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.117. Make Magic Concrete¶
Speed up execution by replacing magic calls by concrete properties.
Magic properties are managed dynamically, with __get``and ``__set. They replace property access by a methodcall, and they are much slower than the first.
When a property name is getting used more often, it is worth creating a concrete property, and skip the method call. The threshold for ‘magicMemberUsage’ is 1, by default.
<?php
class x {
private $values = array('a' => 1,
'b' => 2);
function __get($name) {
return $this->values[$name] ?? '';
}
}
$x = new x();
// Access to 'a' is repeated in the code, at least 'magicMemberUsage' time (cf configuration below)
echo $x->a;
?>
See also Memoize MagicCall.
1.2.117.1. Suggestions¶
Make frequently used properties concrete; keep the highly dynamic as magic
Name |
Default |
Type |
Description |
magicMemberUsage |
1 |
integer |
Minimal number of magic member usage across the code, to trigger a concrete property. |
1.2.117.2. Specs¶
Short name |
Classes/MakeMagicConcrete |
Rulesets |
|
Exakat since |
1.8.3 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.118. Method Is Overwritten¶
This rule marks a method that is overwritten in a child class.
<?php
class A {
function intactMethodA() {} // Not overwritten in any children
function overwrittenMethodInAA() {} // overwritten in AA
}
class AA extends A {
function intactMethodAA() {} // Not overwritten, because no extends
function overwrittenMethodInAA() {} // Not overwritten, because no extends
}
?>
1.2.118.1. Specs¶
Short name |
Classes/MethodIsOverwritten |
Rulesets |
|
Exakat since |
0.10.9 |
PHP Version |
All |
Severity |
|
Time To Fix |
Slow (1 hour) |
Precision |
Very high |
Available in |
1.2.119. Method Signature Must Be Compatible¶
Make sure methods signature are compatible.
PHP generates the infamous Fatal error at execution : Declaration of FooParent\:\:Bar() must be compatible with FooChildren\:\:Bar()
<?php
class x {
function xa() {}
}
class xxx extends xx {
function xa($a) {}
}
?>
1.2.119.1. Suggestions¶
Fix the child class method() signature.
Fix the parent class method() signature, after checking that it won’t affect the other children.
1.2.119.2. Specs¶
Short name |
Classes/MethodSignatureMustBeCompatible |
Rulesets |
|
Exakat since |
1.2.9 |
PHP Version |
All |
Severity |
Critical |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.120. Method Used Below¶
Mark methods that are used in children classes.
<?php
class foo {
// This method is used in children
protected function protectedMethod() {}
// This method is not used in children
protected function localProtectedMethod() {}
private function foobar() {
// protectedMethod is used here, but defined in parent
$this->localProtectedMethod();
}
}
class foofoo extends foo {
private function bar() {
// protectedMethod is used here, but defined in parent
$this->protectedMethod();
}
}
?>
This doesn’t mark the current class, nor the (grand-)`parent <https://www.php.net/manual/en/language.oop5.paamayim-nekudotayim.php>`_ ones.
1.2.120.1. Specs¶
Short name |
Classes/MethodUsedBelow |
Rulesets |
|
Exakat since |
0.12.11 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.121. Mismatch Properties Typehints¶
Properties must match within the same family.
When a property is declared both in a parent class, and a child class, they must have the same type. The same type includes a possible null value.
This doesn’t apply to private properties, which are only visible locally.
<?php
// property $p is declared as an object of type a
class x {
protected A $p;
}
// property $p is declared again, this time without a type
class a extends x {
protected $p;
}
?>
This code will lint, but not execute.
1.2.121.1. Suggestions¶
Remove some of the property declarations, and only keep it in the highest ranking parent
Match the typehints of the property declarations
Make the properties private
Remove the child class (or the parent class)
1.2.121.2. Specs¶
Short name |
Classes/MismatchProperties |
Rulesets |
|
Exakat since |
2.1.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.122. Missing Abstract Method¶
Abstract methods must have a non-abstract version for the class to be complete. A class that is missing one abstract definition cannot be instantiated.
<?php
// This is a valid definition
class b extends a {
function foo() {}
function bar() {}
}
// This compiles, but will emit a fatal error if instantiated
class c extends a {
function bar() {}
}
// This illustration lint but doesn't run.
// moving this class at the beginning of the code will make lint fail
abstract class a {
abstract function foo() ;
}
?>
See also Classes Abstraction.
1.2.122.1. Suggestions¶
Implement the missing methods
Remove the partially implemented class
Mark the partially implemented class abstract
1.2.122.2. Specs¶
Short name |
Classes/MissingAbstractMethod |
Rulesets |
|
Exakat since |
2.1.0 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.123. Multiple Classes In One File¶
It is regarded as a bad practice to store several classes in the same file. This is usually done to make life of __autoload() easier.
It is often unexpected to find class foo in the bar.php file. This is also the case for interfaces and traits.
<?php
// three classes in the same file
class foo {}
class bar {}
class foobar{}
?>
One good reason to have multiple classes in one file is to reduce include time by providing everything into one nice include.
See also Is it a bad practice to have multiple classes in the same file?.
1.2.123.1. Suggestions¶
Split the file into smaller files, one for each class
1.2.123.2. Specs¶
Short name |
Classes/MultipleClassesInFile |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.124. Multiple Class Declarations¶
It is possible to declare several times the same class in the code. PHP will not mention it until execution time, since declarations may be conditional.
<?php
$a = 1;
// Conditional declaration
if ($a == 1) {
class foo {
function method() { echo 'class 1';}
}
} else {
class foo {
function method() { echo 'class 2';}
}
}
(new foo())->method();
?>
It is recommended to avoid declaring several times the same class in the code. The best practice is to separate them with namespaces, they are for here for that purpose. In case those two classes are to be used interchangeably, the best is to use an abstract class or an interface.
1.2.124.1. Suggestions¶
Store classes with different names in different namespaces
Change the name of the classes and give them a common interface to allow from common behavior
1.2.124.2. Specs¶
Short name |
Classes/MultipleDeclarations |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.125. Multiple Property Declaration On One Line¶
Multiple properties are defined on the same line. They could be defined independently, on separate expressions.
Keeping properties separate helps documenting and refactoring them independently.
<?php
// multiple definition on one expression
class point {
private $x, $y, $z;
// more code
}
// one line, one definition
class point2 {
private $x;
private $y;
private $z;
// more code
}
?>
1.2.125.1. Suggestions¶
Split the definitions to one by line
1.2.125.2. Specs¶
Short name |
Classes/MultiplePropertyDeclarationOnOneLine |
Rulesets |
|
Exakat since |
2.2.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Available in |
1.2.126. Multiple Identical Trait Or Interface¶
There is no need to use the same trait, or implements the same interface more than once.
Up to PHP 7.1 (at least), this doesn’t raise any warning. Traits are only imported once, and interfaces may be implemented as many times as wanted.
<?php
class foo {
use t3,t3,t3;
}
class bar implements i,i,i {
}
?>
1.2.126.1. Suggestions¶
Remove the duplicate trait or interfaces
1.2.126.2. Specs¶
Short name |
Classes/MultipleTraitOrInterface |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.127. Classes Mutually Extending Each Other¶
Those classes are extending each other, creating an extension loop. PHP will yield a fatal error at running time, even if it is compiling the code.
<?php
// This code is lintable but won't run
class Foo extends Bar { }
class Bar extends Foo { }
// The loop may be quite large
class Foo extends Bar { }
class Bar extends Bar2 { }
class Bar2 extends Foo { }
?>
1.2.127.1. Specs¶
Short name |
Classes/MutualExtension |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.128. New On Functioncall Or Identifier¶
Object instantiation with new works with or without arguments. Both are valid in PHP.
The analyzed code has less than 10% of one of the two forms : for consistency reasons, it is recommended to make them all the same.
<?php
$a = new stdClass();
// Parenthesis are used when arguments are compulsory
$mysql = new MySQLI($host, $user, $pass);
// Parenthesis are omitted when no arguments are available
// That also makes the instantiation look different
$b = new stdClass;
?>
1.2.128.1. Specs¶
Short name |
Classes/NewOnFunctioncallOrIdentifier |
Rulesets |
|
Exakat since |
0.9.8 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.129. No Magic Method With Array¶
Magic method
__set()doesn’t work for array syntax.
When overloading properties, they can only be used for scalar values, excluding arrays. Under the hood, PHP uses __get() to reach for the name of the property, and doesn’t recognize the following index as an array. It yields an error : Indirect modification of overloaded property.
<?php
class c {
private $a;
private $o = array();
function __get($name) {
return $this->o[$name];
}
function foo() {
// property b doesn't exists
$this->b['a'] = 3;
print_r($this);
}
// This method has no impact on the issue
function __set($name, $value) {
$this->o[$name] = $value;
}
}
$c = new c();
$c->foo();
?>
It is possible to use the array syntax with a magic property : by making the __get returns an array, the syntax will actually extract the expected item in the array.
This is not reported by linting.
In this analysis, only properties that are found to be magic are reported. For example, using the b property outside the class scope is not reported, as it would yield too many false-positives.
See also Overload.
1.2.129.1. Suggestions¶
Use a distinct method to append a new value to that property
Assign the whole array, and not just one of its elements
1.2.129.2. Specs¶
Short name |
Classes/NoMagicWithArray |
Rulesets |
|
Exakat since |
0.12.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
Medium |
Available in |
1.2.130. self, parent, static Outside Class¶
self, parent and static may be used in a trait : their actual value will be only known at execution time, when the trait is used.
<?php
// In the examples, self, parent and static may be used interchangeably
// This raises a Fatal error
//Fatal error: Uncaught Error: Cannot access static:: when no class scope is active
new static();
// static calls
echo self::CONSTANTE;
echo self::$property;
echo self::method();
// as a type hint
function foo(static $x) {
doSomething();
}
// as a instanceof
if ($x instanceof static) {
doSomething();
}
?>
Such syntax problem is only revealed at execution time : PHP raises a Fatal error.
The origin of the problem is usually a method that was moved outside a class, at least temporarily.
See also Scope Resolution Operator (::).
1.2.130.1. Specs¶
Short name |
Classes/NoPSSOutsideClass |
Rulesets |
|
Exakat since |
0.10.3 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.131. Class Without Parent¶
Classes should not refer to
parentwhen it is not extending another class.
In PHP 7.4, it is a Deprecated warning. In PHP 7.3, it was a Fatal error, when the code was finally executed.
<?php
class x {
function foo() {
parent::foo();
}
}
?>
1.2.131.1. Suggestions¶
Update the class and make it extends another class
Change the parent mention with a fully qualified name
Remove the call to the parent altogether
1.2.132. No Public Access¶
The properties below are declared with public access, but are never used publicly. They can be made protected or private.
<?php
class foo {
public $bar = 1; // Public, and used in public space
public $neverInPublic = 3; // Public, but never used in outside the class
function bar() {
$neverInPublic++;
}
}
$x = new foo();
$x->bar = 3;
$x->bar();
?>
1.2.132.1. Specs¶
Short name |
Classes/NoPublicAccess |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.133. No Self Referencing Constant¶
It is not possible to use a constant to define itself in a class. It yields a fatal error at runtime.
The PHP error reads : Cannot declare `self <https://www.php.net/manual/en/language.oop5.paamayim-nekudotayim.php>`_-referencing constant '`self <https://www.php.net/manual/en/language.oop5.paamayim-nekudotayim.php>`_\:\:C2'. Unlike PHP which is self-referencing, self referencing variables can’t have a value : just don’t use that.
<?php
class a {
const C1 = 1; // fully defined constant
const C2 = self::C2; // self referencing constant
const C3 = a::C3 + 2; // self referencing constant
}
?>
The code may access an already declared constant with self or with its class name.
<?php
class a {
const C1 = 1;
const C2 = a::C1;
}
?>
This error is not detected by linting. It is only detected at instantiation time : if the class is not used, it won’t appear.
1.2.133.1. Suggestions¶
Give a literal value to this constant
Give a constant value to this constant : other class constants or constant are allowed here.
1.2.133.2. Specs¶
Short name |
Classes/NoSelfReferencingConstant |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.134. Non Nullable Getters¶
A getter needs to be nullable when a property is injected.
In particular, if the injection happens with a separate method, there is a time where the object is not consistent, and the property holds a default non-object value.
<?php
class Consistent {
private $db = null;
function __construct(Db $db) {
$this->db = $db;
// Object is immediately consistent
}
// Db might be null
function getDb() {
return $this->db;
}
}
class Inconsistent {
private $db = null;
function __construct() {
// No initialisation
}
// This might be called on time, or not
// This typehint cannot be nullable, nor use null as default
function setDb(DB $db) {
return $this->db;
}
// Db might be null
function getDb() {
return $this->db;
}
}
?>
1.2.134.1. Suggestions¶
Remove the nullable option and the tests on
null.
1.2.134.2. Specs¶
Short name |
Classes/NonNullableSetters |
Rulesets |
|
Exakat since |
1.9.6 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.135. Forgotten Visibility¶
Some classes elements (property, method, constant) are missing their explicit visibility.
By default, it is public. It should at least be mentioned as public, or may be reviewed as protected or private.
Class constants support also visibility since PHP 7.1.
final, static and abstract are not counted as visibility. Only public, private and protected. The PHP 4 var keyword is counted as undefined.
Traits, classes and interfaces are checked.
<?php
// Explicit visibility
class X {
protected sconst NO_VISIBILITY_CONST = 1; // For PHP 7.2 and later
private $noVisibilityProperty = 2;
public function Method() {}
}
// Missing visibility
class X {
const NO_VISIBILITY_CONST = 1; // For PHP 7.2 and later
var $noVisibilityProperty = 2; // Only with var
function NoVisibilityForMethod() {}
}
?>
See also Visibility and Understanding The Concept Of Visibility In Object Oriented PHP.
1.2.135.1. Suggestions¶
Always add explicit visibility to methods and constants in a class
Always add explicit visibility to properties in a class, after PHP 7.4
1.2.135.2. Specs¶
Short name |
Classes/NonPpp |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
ClearPHP |
|
Examples |
|
Available in |
1.2.136. Non Static Methods Called In A Static¶
PHP 7.0, and more recent versions, yield a deprecated error : Non-`static <https://www.php.net/manual/en/language.oop5.static.php>`_ method A\:\:B() should not be called statically.
PHP 5 and older doesn’t check that a method is static or not : at any point, the code may call one method statically.
<?php
class x {
static public function sm( ) { echo __METHOD__.\n; }
public public sm( ) { echo __METHOD__.\n; }
}
x::sm( ); // echo x::sm
// Dynamic call
['x', 'sm']();
[\x::class, 'sm']();
$s = 'x::sm';
$s();
?>
It is a bad idea to call non-static method statically. Such method may make use of special variable $this, which will be undefined. PHP will not check those calls at compile time, nor at running time.
It is recommended to update this situation : make the method actually static, or use it only in object context.
Note that this analysis reports all static method call made on a non-static method, even within the same class or class hierarchy. PHP silently accepts static call to any in-family method.
<?php
class x {
public function foo( ) { self::bar() }
public function bar( ) { echo __METHOD__.\n; }
}
?>
See also Static Keyword <https://www.php.net/manual/en/language.oop5.`static.php>`_.
1.2.136.1. Suggestions¶
Call the method the correct way
Define the method as static
1.2.136.2. Specs¶
Short name |
Classes/NonStaticMethodsCalledStatic |
Rulesets |
Analyze, CE, CI-checks, CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, All |
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Medium |
Examples |
|
Available in |
1.2.137. Normal Methods¶
Spot normal Methods.
<?php
class foo{
// Normal method
private function bar() {}
// Static method
private static function barbar() {}
}
?>
1.2.137.1. Specs¶
Short name |
Classes/NormalMethods |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.138. Null On New¶
Until PHP 7, some classes instantiation could yield null, instead of throwing an exception.
After issuing a ‘new’ with those classes, it was important to check if the returned object were null or not. No exception were thrown.
<?php
// Example extracted from the wiki below
$mf = new MessageFormatter('en_US', '{this was made intentionally incorrect}');
if ($mf === null) {
echo 'Surprise!';
}
?>
This inconsistency has been cleaned in PHP 7 : see See Internal Constructor Behavior
See also PHP RFC: Constructor behaviour of internal classes.
1.2.138.1. Suggestions¶
Remove the check on null after a new instantiation
1.2.138.2. Specs¶
Short name |
Classes/NullOnNew |
Rulesets |
CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, All |
Exakat since |
0.8.4 |
PHP Version |
7.0- |
Severity |
Major |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.139. Old Style Constructor¶
PHP classes used to have the method bearing the same name as the class acts as the constructor. That was PHP 4, and early PHP 5.
The manual issues a warning about this syntax : Old style constructors are DEPRECATED in PHP 7.0, and will be removed in a future version. You should always use `__construct() <https://www.php.net/manual/en/language.oop5.decon.php>`_ in new code.
<?php
namespace {
// Global namespace is important
class foo {
function foo() {
// This acts as the old-style constructor, and is reported by PHP
}
}
class bar {
function __construct() { }
function bar() {
// This doesn't act as constructor, as bar has a __construct() method
}
}
}
namespace Foo\Bar{
class foo {
function foo() {
// This doesn't act as constructor, as bar is not in the global namespace
}
}
}
?>
This is no more the case in PHP 5, which relies on __construct() to do so. Having this old style constructor may bring in confusion, unless you are also supporting old time PHP 4.
Note that classes with methods bearing the class name, but inside a namespace are not following this convention, as this is not breaking backward compatibility. Those are excluded from the analyze.
See also Constructors and Destructors.
1.2.139.1. Suggestions¶
Remove old style constructor and make it
__construct()Remove old libraries and use a modern component
1.2.139.2. Specs¶
Short name |
Classes/OldStyleConstructor |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
ClearPHP |
|
Available in |
1.2.140. Var Keyword¶
Var was used in PHP 4 to mark properties as public. Nowadays, new keywords are available : public, protected, private. Var is equivalent to public.
It is recommended to avoid using var, and explicitly use the new keywords.
<?php
class foo {
public $bar = 1;
// Avoid var
//var $bar = 1;
}
?>
See also Visibility.
1.2.140.1. Suggestions¶
It is recommended to avoid using var, and explicitly use the new keywords : private, protected, public
1.2.140.2. Specs¶
Short name |
Classes/OldStyleVar |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
ClearPHP |
|
Examples |
|
Available in |
1.2.141. One Object Operator Per Line¶
Avoid using more than one operator -> per line, to prevent information overload.
<?php
// Spread operators on multiple lines
$object->firstMethodCall()
->property
->secondMethodCall();
// This is not readable
$object->firstMethodCall()->property->secondMethodCall();
// This is OK, as objects are different.
$a2->b2($c2->d2, $e2->f2);
?>
1.2.141.1. Specs¶
Short name |
Classes/OneObjectOperatorPerLine |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.142. Only Static Methods¶
Marks a class that has only static methods.
1.2.142.1. Specs¶
Short name |
Classes/OnlyStaticMethods |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.143. Order Of Declaration¶
The order used to declare members and methods has a great impact on readability and maintenance. However, practices varies greatly. As usual, being consistent is the most important and useful.
The suggested order is the following : traits, constants, properties, methods. Optional characteristics, like final, static… are not specified. Special methods names are not specified.
<?php
class x {
use traits;
const CONSTANTS = 1;
const CONSTANTS2 = 1;
const CONSTANTS3 = 1;
private $property = 2;
private $property2 = 2;
private $property3 = 2;
public function foo() {}
public function foo2() {}
public function foo3() {}
public function foo4() {}
}
?>
1.2.143.1. Suggestions¶
Always declare class elements (traits, constants, properties, methods) in the same order.
1.2.143.2. Specs¶
Short name |
Classes/OrderOfDeclaration |
Rulesets |
|
Exakat since |
0.11.7 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
Medium |
Available in |
1.2.144. Overwritten Class Const¶
Those class constants are overwritten in a parent class. This may lead to confusion, as the value of the constant may change depending on the way it is called.
<?php
class foo {
const C = 1;
}
class bar extends foo {
const C = 2;
function x() {
// depending on the access to C, value is different.
print self::C.' '.static::C.' '.parent::C;
}
}
?>
1.2.144.1. Specs¶
Short name |
Classes/OverwrittenConst |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.145. Properties Declaration Consistence¶
Properties may be declared all at once, or one by one.
The analyzed code has less than 10% of one of them : for consistency reasons, it is recommended to make them all the same.
It happens that choosing unique declarations or multiple depends on coding style and files.
<?php
class x {
// Some declarations are made by batch
private $a1 = 1,
$a2 = 2;
public $c = 1, $c2 = 2, $c4 = 3;
// Most declarations are made one by one
protected $b = 1;
protected $b1 = 1;
protected $b2 = 1;
protected $b3 = 1;
protected $b4 = 1;
protected $b5 = 1;
protected $b6 = 1;
protected $b7 = 1;
protected $b8 = 1;
protected $b9 = 1;
protected $b10 = 1;
protected $b11 = 1;
protected $b12 = 1;
protected $b13 = 1;
protected $b14 = 1;
protected $b15 = 1;
protected $b16 = 1;
protected $b17 = 1;
protected $b18 = 1;
protected $b19 = 1;
}
?>
See also Properties.
1.2.145.1. Specs¶
Short name |
Classes/PPPDeclarationStyle |
Rulesets |
|
Exakat since |
1.2.1 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.146. Parent First¶
<?php
class father {
protected $name = null;
function __construct() {
$this->name = init();
}
}
class goodSon {
function __construct() {
// parent is build immediately,
parent::__construct();
echo my name is.$this->name;
}
}
class badSon {
function __construct() {
// This will fail.
echo my name is.$this->name;
// parent is build later,
parent::__construct();
}
}
?>
This analysis doesn’t apply to Exceptions.
1.2.146.1. Suggestions¶
Use
parent\:\:__constructas the first call in the constructor.
1.2.146.2. Specs¶
Short name |
Classes/ParentFirst |
Rulesets |
|
Exakat since |
1.0.5 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.147. Property Could Be Local¶
A property only used in one method may be turned into a local variable.
Public an protected properties are omitted here : they may be modified somewhere else, in the code. This analysis may be upgraded to support those properties, when tracking of such properties becomes available.
Classes where only one non-magic method is available are omitted.
Traits with private properties are processed the same way.
<?php
class x {
private $foo = 1;
// Magic method, and constructor in particular, are omitted.
function __construct($foo) {
$this->foo = $foo;
}
function bar() {
$this->foo++;
return $this->foo;
}
function barbar() {}
}
?>
1.2.147.1. Suggestions¶
Remove the property and make it an argument in the method
Use that property elsewhere
1.2.147.2. Specs¶
Short name |
Classes/PropertyCouldBeLocal |
Rulesets |
|
Exakat since |
1.1.7 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Examples |
|
Available in |
1.2.148. Property Names¶
Variables are used in property definitions, when they are located in a class.
<?php
static $x; // not a property, a static variable
class foo {
static $x; // now, this is a static property
public $y, $z = 1; // normal properties
public function bar() {
static $x; // again, a static variable
}
}
?>
See also Properties.
1.2.148.1. Specs¶
Short name |
Classes/PropertyDefinition |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.149. Never Used Properties¶
Properties that are never used. They are defined in a class or a trait, but they never actually used.
Properties are considered used when they are used locally, in the same class as their definition, or in a parent class : a parent class is always included with the current class.
On the other hand, properties which are defined in a class, but only used in children classes is considered unused, since children may also avoid using it.
<?php
class foo {
public $usedProperty = 1;
// Never used anywhere
public $unusedProperty = 2;
function bar() {
// Used internally
++$this->usedProperty;
}
}
class foo2 extends foo {
function bar2() {
// Used in child class
++$this->usedProperty;
}
}
// Used externally
++$this->usedProperty;
?>
1.2.149.1. Suggestions¶
Drop unused properties
Change the name of the unused properties
Move the properties to children classes
Find usage for unused properties
1.2.149.2. Specs¶
Short name |
Classes/PropertyNeverUsed |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Examples |
|
Available in |
1.2.150. Property Used Above¶
It may also be used in the current class, or its children, though this is not reported by this analyzer.
<?php
class A {
public function foo() {
$this->pb++;
}
}
class B extends A {
protected $pb = 0; // property used above
protected $pb2 = 0; // property NOT used above
}
?>
See also Property Used Below.
1.2.150.1. Suggestions¶
Move the definition of the property to the upper class
Move the usage of the property to the lower class
1.2.150.2. Specs¶
Short name |
Classes/PropertyUsedAbove |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
|
Time To Fix |
Slow (1 hour) |
Precision |
Medium |
Available in |
1.2.151. Property Used Below¶
Mark properties that are used in children classes.
<?php
class foo {
// This property is used in children
protected protectedProperty = 1;
// This property is not used in children
protected localProtectedProperty = 1;
private function foobar() {
// protectedProperty is used here, but defined in parent
$this->localProtectedProperty = 3;
}
}
class foofoo extends foo {
private function bar() {
// protectedProperty is used here, but defined in parent
$this->protectedProperty = 3;
}
}
?>
This doesn’t mark the current class, nor the (grand-)`parent <https://www.php.net/manual/en/language.oop5.paamayim-nekudotayim.php>`_ ones.
1.2.151.1. Specs¶
Short name |
Classes/PropertyUsedBelow |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
Medium |
Available in |
1.2.152. Property Used In One Method Only¶
Properties should be used in several methods. When a property is used in only one method, this should have be of another shape.
Properties used in one method only may be used several times, and read only. This may be a class constant. Such properties are meant to be overwritten by an extending class, and that’s possible with class constants.
Properties that read and written may be converted into a variable, static to the method. This way, they are kept close to the method, and do not pollute the object’s properties.
<?php
class foo {
private $once = 1;
const ONCE = 1;
private $counter = 0;
function bar() {
// $this->once is never used anywhere else.
someFunction($this->once);
someFunction(self::ONCE); // Make clear that it is a
}
function bar2() {
static $localCounter = 0;
$this->counter++;
// $this->once is only used here, for distinguising calls to someFunction2
if ($this->counter > 10) { // $this->counter is used only in bar2, but it may be used several times
return false;
}
someFunction2($this->counter);
// $localCounter keeps track for all the calls
if ($localCounter > 10) {
return false;
}
someFunction2($localCounter);
}
}
?>
Note : properties used only once are not returned by this analysis. They are omitted, and are available in the analysis Used Once Property.
1.2.152.1. Suggestions¶
Drop the property, and inline the value
Drop the property, and make the property a local variable
Use the property in another method
1.2.152.2. Specs¶
Short name |
Classes/PropertyUsedInOneMethodOnly |
Rulesets |
|
Exakat since |
0.10.3 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Examples |
|
Available in |
1.2.153. Internally Used Properties¶
Properties that are used internally.
<?php
class x {
public $internallyUsedProperty = 1;
public $externallyUsedProperty = 1;
public $alsoExternallyUsedProperty = 1;
function foo() {
$this->internallyUsedProperty = 2;
}
}
class y extends x {
function bar() {
$this->externallyUsedProperty = 3;
}
}
$X = new x();
$X->alsoExternallyUsedProperty = 3;
?>
1.2.153.1. Specs¶
Short name |
Classes/PropertyUsedInternally |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.154. Parent, Static Or Self Outside Class¶
PHP 7.0 and later detect their usage at compile time, and emits a fatal error.
<?php
class x {
const Y = 1;
function foo() {
// self is \x
echo self::Y;
}
}
const Z = 1;
// This lint but won't anymore
echo self::Z;
?>
Static may be used in a function or a closure, but not globally. See also and .
1.2.154.1. Specs¶
Short name |
Classes/PssWithoutClass |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
With PHP 7.0 and older |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.155. Raised Access Level¶
A property’s visibility may be lowered, but not raised.
This error may be detected when the classes are all in the same file : then, PHP reports the problem. However, when the classes are separated in different files, as it is customary, PHP won’t check this at linting time, yielding a fatal error at execution time.
First file.
<?php
class Foo {
public $publicProperty;
protected $protectedProperty;
private $privateProperty;
}
?>
Second file.
<?php
class Bar extends Foo {
private $publicProperty;
private $protectedProperty;
private $privateProperty; // This one is OK
}
?>
See also Visibility and Understanding the concept of visibility in object oriented php.
1.2.155.1. Suggestions¶
Lower the visibility in the child class
Raise the visibility in the parent class
1.2.155.2. Specs¶
Short name |
Classes/RaisedAccessLevel |
Rulesets |
|
Exakat since |
0.10.0 |
PHP Version |
All |
Severity |
Critical |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.156. Redefined Class Constants¶
Redefined class constants.
Class constants may be redefined, though it is prone to errors when using them, as it is now crucial to use the right class name to access the right value.
<?php
class a {
const A = 1;
}
class b extends a {
const A = 2;
}
class c extends c { }
echo a::A, ' ', b::A, ' ', c::A;
// 1 2 2
?>
It is recommended to use distinct names.
1.2.156.1. Specs¶
Short name |
Classes/RedefinedConstants |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.157. Redefined Default¶
Classes allows properties to be set with a default value. When those properties get, unconditionally, another value at constructor time, then one of the default value are useless. One of those definition should go : it is better to define properties outside the constructor.
<?php
class foo {
public $redefined = 1;
public function __construct( ) {
$this->redefined = 2;
}
}
?>
1.2.157.1. Suggestions¶
Move the default assignation to the property definition
Drop the reassignation in the constructor
1.2.157.2. Specs¶
Short name |
Classes/RedefinedDefault |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Examples |
|
Available in |
1.2.158. Redefined Methods¶
Redefined methods are overwritten methods. Those methods are defined in different classes that are part of the same classes hierarchy.
Protected and public redefined methods replace each other. Private methods are kept separated, and depends on the caller to be distinguished.
<?php
class foo {
function method() {
return 1;
}
}
class bar extends foo {
function method() {
return 2;
}
}
?>
See also Object Inheritance.
1.2.158.1. Specs¶
Short name |
Classes/RedefinedMethods |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.159. Redefined Private Property¶
Private properties are local to their defined class. PHP doesn’t forbid the re-declaration of a private property in a child class.
However, having two or more properties with the same name, in the class hierarchy tends to be error prone.
<?php
class A {
private $isReady = true;
}
class B {
private $isReady = false;
}
?>
1.2.159.1. Specs¶
Short name |
Classes/RedefinedPrivateProperty |
Rulesets |
|
Exakat since |
1.2.3 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Examples |
|
Available in |
1.2.160. Redefined Property¶
Property redefined in a parent class.
Using heritage, it is possible to define several times the same property, at different levels of the hierarchy.
<?php
class foo {
protected $aProperty = 1;
}
class bar extends foo {
// This property is redefined in the parent class, leading to potential confusion
protected $aProperty = 1;
}
?>
When this is the case, it is difficult to understand which class will actually handle the property.
In the case of a private property, the different instances will stay distinct. In the case of protected or public properties, they will all share the same value.
It is recommended to avoid redefining the same property in a hierarchy.
1.2.160.1. Suggestions¶
Remove of the definition
1.2.160.2. Specs¶
Short name |
Classes/RedefinedProperty |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Available in |
1.2.161. Not Same Name As File¶
The class, interface or trait in this file as a different name, case included, than the file name.
In the following example, the file name is Foo.php.
.. code-block:: php
<?php
// normal host of this file class Foo {
// some code
}
// case-typo this file class foo {
// some code
}
// strangely stored class class foo {
// some code
}
// This is valid name, but there is also a Foo class, and other classe in this file. interface Foo {}
?>
1.2.161.1. Specs¶
Short name |
Classes/SameNameAsFile |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.162. Scalar Or Object Property¶
Property shouldn’t use both object and scalar syntaxes. When a property may be an object, it is recommended to implement the Null Object pattern : instead of checking if the property is scalar, make it always object.
<?php
class x {
public $display = 'echo';
function foo($string) {
if (is_string($this->display)) {
echo $this->string;
} elseif ($this->display instanceof myDisplayInterface) {
$display->display();
} else {
print Error when displaying\n;
}
}
}
interface myDisplayInterface {
public function display($string); // does the display in its own way
}
class nullDisplay implements myDisplayInterface {
// implements myDisplayInterface but does nothing
public function display($string) {}
}
class x2 {
public $display = null;
public function __construct() {
$this->display = new nullDisplay();
}
function foo($string) {
// Keep the check, as $display is public, and may get wrong values
if ($this->display instanceof myDisplayInterface) {
$display->display();
} else {
print Error when displaying\n;
}
}
}
// Simple class for echo
class echoDisplay implements myDisplayInterface {
// implements myDisplayInterface but does nothing
public function display($string) {
echo $string;
}
}
?>
See also Null Object Pattern. and The Null Object Pattern.
1.2.162.1. Suggestions¶
Only use one type of syntax with your properties.
1.2.162.2. Specs¶
Short name |
Classes/ScalarOrObjectProperty |
Rulesets |
|
Exakat since |
0.12.3 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Examples |
|
Available in |
1.2.163. Should Deep Clone¶
By default, PHP makes a shallow clone. It only clone the scalars, and keep the reference to any object already referenced. This means that the cloned object and its original share any object they hold as property.
This is where the magic method __clone() comes into play. It is called, when defined, at clone time, so that the cloned object may clone all the needed sub-objects.
It is recommended to use the __clone() method whenever the objects hold objects.
<?php
class a {
public $b = null;
function __construct() {
$this->b = new Stdclass();
$this->b->c = 1;
}
}
class ab extends a {
function __clone() {
$this->b = clone $this->b;
}
}
// class A is shallow clone, so $a->b is not cloned
$a = new a();
$b = clone $a;
$a->b->c = 3;
echo $b->b->c;
// displays 3
// class Ab is deep clone, so $a->b is cloned
$a = new ab();
$b = clone $a;
$a->b->c = 3;
echo $b->b->c;
// displays 1
?>
See also PHP Clone and Shallow vs Deep Copying and Cloning objects.
1.2.163.1. Specs¶
Short name |
Classes/ShouldDeepClone |
Rulesets |
|
Exakat since |
1.7.0 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.164. Should Have Destructor¶
PHP destructors are called when the object has to be destroyed. By default, PHP calls recursively the destructor on internal objects, until everything is unset.
Unsetting objects and resources explicitly in the destructor is a good practice to reduce the amount of memory in use. It helps PHP resource counter to keep the numbers low, and easier to clean. This is a major advantage for long running scripts.
<?php
class x {
function __construct() {
$this->p = new y();
}
function __destruct() {
print __METHOD__.PHP_EOL;
unset($this->p);
}
}
class y {
function __construct() {
print __METHOD__.PHP_EOL;
$this->p = new y();
}
function __destruct() {
print __METHOD__.PHP_EOL;
unset($this->p);
}
}
$a = (new x);
sleep(1);
// This increment the resource counter by one for the property.
$p = $a->p;
unset($a);
sleep(3);
print 'end'.PHP_EOL;
// Y destructor is only called here, as the object still exists in $p.
?>
See also Destructor, and Php Destructors.
1.2.164.1. Suggestions¶
Add a destruct method to the class to help clean at destruction time.
1.2.164.2. Specs¶
Short name |
Classes/ShouldHaveDestructor |
Rulesets |
|
Exakat since |
1.5.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.165. Could Use self¶
selfkeyword refers to the current class, or any of its parents. Using it is just as fast as the full class name, it is as readable and it is will not be changed upon class or namespace change.
It is also routinely used in traits : there, self represents the class in which the trait is used, or the trait itself.
<?php
class x {
const FOO = 1;
public function bar() {
return self::FOO;
// same as return x::FOO;
}
}
?>
See also Scope Resolution Operator (::).
1.2.165.1. Suggestions¶
replace the explicit name with self
1.2.165.2. Specs¶
Short name |
Classes/ShouldUseSelf |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.166. Should Use Local Class¶
Methods should use the defining class, or be functions.
Methods should use $this with another method or a property, or call parent\:\:. Static methods should call another static method, or a static property.
Methods which are overwritten by a child class are omitted : the parent class act as a default value for the children class, and this is correct.
<?php
class foo {
public function __construct() {
// This method should do something locally, or be removed.
}
}
class bar extends foo {
private $a = 1;
public function __construct() {
// Calling parent:: is sufficient
parent::__construct();
}
public function barbar() {
// This is acting on the local object
$this->a++;
}
public function barfoo($b) {
// This has no action on the local object. It could be a function or a closure where needed
return 3 + $b;
}
}
?>
Note that a method using a class constant is not considered as using the local class, for this analyzer.
1.2.166.1. Suggestions¶
Make this method a function
Actually use $this, or any related attributes of the class
1.2.166.2. Specs¶
Short name |
Classes/ShouldUseThis |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
ClearPHP |
|
Available in |
1.2.167. Static Methods Can’t Contain $this¶
<?php
class foo {
// Static method may access other static methods, or property, or none.
static function staticBar() {
// This is not possible in a static method
return self::otherStaticBar() . static::$staticProperty;
}
static function bar() {
// This is not possible in a static method
return $this->property;
}
}
?>
Either this is not a static method, which is fixed by removing the static keyword, or replace all $this mention by static properties Class\:\:$property.
See also Static Keyword <https://www.php.net/manual/en/language.oop5.`static.php>`_
1.2.167.1. Suggestions¶
Remove any $this usage
Turn any $this usage into a static call : $this->foo() => self::foo()
1.2.167.2. Specs¶
Short name |
Classes/StaticContainsThis |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
ClearPHP |
|
Examples |
|
Available in |
1.2.168. Static Methods¶
List of all static methods.
<?php
class foo {
static public function staticMethod() {
}
public function notStaticMethod() {
}
private function method() {
// This is not a property
new static();
}
}
?>
1.2.168.1. Specs¶
Short name |
Classes/StaticMethods |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.169. Static Methods Called From Object¶
Besides this, static methods are normal methods that may be called directly from object context, to perform some utility task.
To maintain code readability, it is recommended to call static method in a static way, rather than within object context.
<?php
class x {
static function y( ) {}
}
$z = new x( );
$z->y( ); // Readability : no one knows it is a static call
x::y( ); // Readability : here we know
?>
1.2.169.1. Suggestions¶
Switch to static method syntax
Remove the static option from the method
1.2.169.2. Specs¶
Short name |
Classes/StaticMethodsCalledFromObject |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.170. Static Properties¶
List of all static properties.
<?php
class foo {
static public $staticProperty = 1;
public $notStaticProperty = 2;
private function method() {
// This is not a property
new static();
}
}
function bar() {
// This is not a static property
static $staticVariable;
//....
}
?>
1.2.170.1. Specs¶
Short name |
Classes/StaticProperties |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.171. Strange Names For Methods¶
Those methods should have another name.
Ever wondered why the __constructor is never called? Or the __consturct ?
Those errors most often originate from typos, or quick fixes that where not fully tested. Other times, they were badly chosen, or ran into PHP’s own reserved keywords.
<?php
class foo {
// The real constructor
function __construct() {}
// The fake constructor
function __constructor() {}
// The 'typo'ed' constructor
function __consturct() {}
// This doesn't clone
function clone() {}
}
?>
1.2.171.1. Suggestions¶
Use the proper name
Remove the method, when it is not used and tests still pass.
1.2.171.2. Specs¶
Short name |
Classes/StrangeName |
Rulesets |
|
Exakat since |
0.10.1 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.172. Swapped Arguments¶
Overwritten methods must be compatible, but argument names is not part of that compatibility.
Methods with the same name, in two classes of the same hierarchy, must be compatible for typehint, default value, reference. The name of the argument is not taken into account when checking such compatibility, at least until PHP 7.4.
<?php
class x {
function foo($a, $b) {}
function bar($a, $b) {}
}
class y extends x {
// foo is compatible (identical) with the above class
function foo($a, $b) {}
// bar is compatible with the above class, yet, the argument might not receive what they expect.
function bar($b, $a) {}
}
?>
This analysis reports argument lists that differs in ordering. This analysis doesn’t report argument lists that also differs in argument names.
1.2.172.1. Suggestions¶
Make sure the names of the argument are in the same order in all classes and interfaces
1.2.172.2. Specs¶
Short name |
Classes/SwappedArguments |
Rulesets |
|
Exakat since |
2.1.5 |
PHP Version |
All |
Severity |
Critical |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.173. Test Class¶
Those are test classes, based on popular UT frameworks.
1.2.173.1. Specs¶
Short name |
Classes/TestClass |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.174. $this Belongs To Classes Or Traits¶
$this variable represents the current object, inside a class or trait scope.
It is a pseudo-variable, and should be used within class’s or trait’s methods and not outside. It should also not be used in static methods.
PHP 7.1 is stricter and check for $this at several situations.
This analysis also re
<?php
// as an argument
function foo($this) {
// Using global
global $this;
// Using static (not a property)
static $this;
// Can't unset it
unset($this);
try {
// inside a foreach
foreach($a as $this) { }
foreach($a as $this => $b) { }
foreach($a as $b => $this) { }
} catch (Exception $this) {
// inside a catch
}
// with Variable Variable
$a = this;
$$a = 42;
}
class foo {
function bar() {
// Using references
$a =& $this;
$a = 42;
// Using extract(), parse_str() or similar functions
extract([this => 42]); // throw new Error(Cannot re-assign $this)
var_dump($this);
}
static function __call($name, $args) {
// Using __call
var_dump($this); // prints object(C)#1 (0) {}, php-7.0 printed NULL
$this->test(); // prints ops
}
}
?>
1.2.174.1. Suggestions¶
Do not use $this as a variable name, except for the current object, in a class, trait or closure.
1.2.174.2. Specs¶
Short name |
Classes/ThisIsForClasses |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Examples |
|
Available in |
1.2.175. $this Is Not An Array¶
$thisvariable represents the current object and it is not an array.
This is unless the class (or its parents) has the ArrayAccess interface, or extends ArrayObject or SimpleXMLElement.
<?php
// $this is an array
class Foo extends ArrayAccess {
function bar() {
++$this[3];
}
}
// $this is not an array
class Foo2 {
function bar() {
++$this[3];
}
}
?>
See also ArrayAccess, ArrayObject and The Basics.
1.2.175.1. Suggestions¶
Extends
ArrayObject, or a class that extends it, to use$thisas an array too.Implements
ArrayAccessto use$thisas an array too.Use a property in the current class to store the data, instead of $this directly.
1.2.175.2. Specs¶
Short name |
Classes/ThisIsNotAnArray |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.176. $this Is Not For Static Methods¶
$this variable represents an object, the current object. It is not compatible with a static method, which may operate without any object.
While executing a static method, $this is actually set to NULL.
<?php
class foo {
static $staticProperty = 1;
// Static methods should use static properties
static public function count() {
return self::$staticProperty++;
}
// Static methods can't use $this
static public function bar() {
return $this->a; // No $this usage in a static method
}
}
?>
See also Static Keyword <https://www.php.net/manual/en/language.oop5.`static.php>`_.
1.2.176.1. Suggestions¶
Remove the static keyword on the method, and update all calls to this method to use $this
Remove the usage of $this in the method, replacing it with static properties
Make $this an argument (and change its name) : then, make the method a function
1.2.176.2. Specs¶
Short name |
Classes/ThisIsNotForStatic |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
ClearPHP |
|
Available in |
1.2.177. Throw In Destruct¶
According to the manual,
Attempting to throw an exception from a destructor (called in the time of script termination) causes a fatal error.
The destructor may be called during the lifespan of the script, but it is not certain. If the exception is thrown later, the script may end up with a fatal error.
Thus, it is recommended to avoid throwing exceptions within the __destruct method of a class.
<?php
// No exception thrown
class Bar {
function __construct() {
throw new Exception('__construct');
}
function __destruct() {
$this->cleanObject();
}
}
// Potential crash
class Foo {
function __destruct() {
throw new Exception('__destruct');
}
}
?>
See also Constructors and Destructors.
1.2.177.1. Suggestions¶
Remove any exception thrown from a destructor
1.2.177.2. Specs¶
Short name |
Classes/ThrowInDestruct |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.178. Too Many Children¶
Classes that have more than 15 children. It is worth checking if they cannot be refactored in anyway.
The threshold of 15 children can be configured. There is no technical limitation of the number of children and grand-children for a class.
The analysis doesn’t work recursively : only direct generations are counted. Only children that can be found in the code are counted.
<?php
// parent class
// calling it grandparent to avoid confusion with 'parent'
class grandparent {}
class children1 extends grandparent {}
class children2 extends grandparent {}
class children3 extends grandparent {}
class children4 extends grandparent {}
class children5 extends grandparent {}
class children6 extends grandparent {}
class children7 extends grandparent {}
class children8 extends grandparent {}
class children9 extends grandparent {}
class children11 extends grandparent {}
class children12 extends grandparent {}
class children13 extends grandparent {}
class children14 extends grandparent {}
class children15 extends grandparent {}
class children16 extends grandparent {}
class children17 extends grandparent {}
class children18 extends grandparent {}
class children19 extends grandparent {}
?>
See also Why is subclassing too much bad (and hence why should we use prototypes to do away with it)?.
1.2.178.1. Suggestions¶
Split the original class into more specialised classes
Name |
Default |
Type |
Description |
childrenClassCount |
15 |
integer |
Threshold for too many children classes for one class. |
1.2.178.2. Specs¶
Short name |
Classes/TooManyChildren |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Examples |
|
Available in |
1.2.179. Too Many Dereferencing¶
Linking too many properties and methods, one to the other.
This analysis counts both static calls and normal call; methods, properties and constants. It also takes into account arrays along the way.
The default limit of chaining methods and properties is set to 7 by default.
<?php
// 9 chained calls.
$main->getA()->getB()->getC()->getD()->getE()->getF()->getG()->getH()->getI()->property;
?>
Too many chained methods is harder to read.
Name |
Default |
Type |
Description |
tooManyDereferencing |
7 |
integer |
Maximum number of dereferencing. |
1.2.179.1. Specs¶
Short name |
Classes/TooManyDereferencing |
Rulesets |
|
Exakat since |
1.9.7 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.180. Too Many Finds¶
Too many methods called ‘find*’ in this class. It is may be time to consider the Specification pattern.
<?php
// quite a fishy interface
interface UserInterface {
public function findByEmail($email);
public function findByUsername($username);
public function findByFirstName($firstname);
public function findByLastName($lastname);
public function findByName($name);
public function findById($id);
public function insert($user);
public function update($user);
}
?>
See also On Taming Repository Classes in Doctrine , On Taming Repository Classes in Doctrine… Among other things., specifications.
Name |
Default |
Type |
Description |
minimumFinds |
5 |
integer |
Minimal number of prefixed methods to report. |
findPrefix |
find |
string |
list of prefix to use when detecting the ‘find’. Comma-separated list, case insensitive. |
findSuffix |
string |
list of fix to use when detecting the ‘find’. Comma-separated list, case insensitive. |
1.2.180.1. Specs¶
Short name |
Classes/TooManyFinds |
Rulesets |
|
Exakat since |
0.10.5 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.181. Too Many Injections¶
When a class is constructed with more than four dependencies, it should be split into smaller classes.
<?php
// This class relies on 5 other instances.
// It is probably doing too much.
class Foo {
public function __construct(
A $a,
B $b,
C $c,
D $d
E $e ) {
$this->a = $a;
$this->b = $b;
$this->d = $d;
$this->d = $d;
$this->e = $e;
}
}
?>
See also Dependency Injection Smells.
1.2.181.1. Suggestions¶
Split the class into smaller classes. Try to do less in that class.
Name |
Default |
Type |
Description |
injectionsCount |
5 |
integer |
Threshold for too many injected parameters for one class. |
1.2.181.2. Specs¶
Short name |
Classes/TooManyInjections |
Rulesets |
|
Exakat since |
0.11.6 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Examples |
|
Available in |
1.2.182. DI Cyclic Dependencies¶
When injecting dependencies, classes that mutually depend on each other is a code smell.
Dependency injection should be organized as an acyclic tree-like structure
<?php
// Classes A and B depends on each other.
class A {
protected $b;
public function __construct(B $b) {
$this->b = $b;
}
}
class B {
public $a;
protected function setA(A $a) {
$this->a = $a;
}
}
?>
See also Dependency Injection Smells.
1.2.182.1. Specs¶
Short name |
Classes/TypehintCyclicDependencies |
Rulesets |
|
Exakat since |
0.11.6 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.183. Wrong Access Style to Property¶
Mistaking one of the other raise two different reactions from PHP : Access to undeclared `static <https://www.php.net/manual/en/language.oop5.static.php>`_ property is a fatal error, while PHP Notice: Accessing `static <https://www.php.net/manual/en/language.oop5.static.php>`_ property aa\:\:$a as non `static <https://www.php.net/manual/en/language.oop5.static.php>`_ is a notice.
<?php
class a {
static public $a = 1;
function foo() {
echo self::$a; // right
echo $this->a; // WRONG
}
}
class b {
public $b = 1;
function foo() {
echo $this->$b; // right
echo b::$b; // WRONG
}
}
?>
This analysis reports both static properties with a -> access, and non-static properties with a :: access.
See also Static Keyword <https://www.php.net/manual/en/language.oop5.`static.php>`_.
1.2.183.1. Suggestions¶
Match the property call with the definition
Make the property static
1.2.184. Undefined Classes¶
Those classes are used in the code, but there are no definition for them.
This may happens under normal conditions, if the application makes use of an unsupported extension, that defines extra classes; or if some external libraries, such as PEAR, are not provided during the analysis.
<?php
// FPDF is a classic PDF class, that is usually omitted by Exakat.
$o = new FPDF();
// Exakat reports undefined classes in instanceof
// PHP ignores them
if ($o instanceof SomeClass) {
// doSomething();
}
// Classes may be used in typehint too
function foo(TypeHintClass $x) {
// doSomething();
}
?>
This analysis also checks in attributes.
1.2.184.1. Suggestions¶
Fix the typo in the class name
Add a missing ‘use’ expression
Create the missing class
1.2.184.2. Specs¶
Short name |
Classes/UndefinedClasses |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
Medium |
Available in |
1.2.185. Undefined Class Constants¶
Class constants that are used, but never defined. This should yield a fatal error upon execution, but no feedback at compile level.
<?php
class foo {
const A = 1;
define('B', 2);
}
// here, C is not defined in the code and is reported
echo foo::A.foo::B.foo::C;
?>
1.2.185.1. Suggestions¶
Fix the name of the constant
Add the constant to the current class or one of its parent
Update the constant’s visibility
See also and Class constants.
1.2.185.2. Specs¶
Short name |
Classes/UndefinedConstants |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.186. Undefined Parent¶
List of properties and methods that are accessed using
parentkeyword but are not defined in the parent classes.
This may compile but, eventually yields a fatal error during execution.
<?php
class theParent {
// No bar() method
// private bar() method is not accessible to theChild
}
class theChild extends theParent {
function foo() {
// bar is defined in theChild, but not theParent
parent::bar();
}
function bar() {
}
}
?>
Note that if the parent is defined using extends someClass but someClass is not available in the tested code, it will not be reported : it may be in composer, another dependency, or just missing.
See also parent <https://www.php.net/manual/en/keyword.`parent.php>`_.
1.2.186.1. Suggestions¶
Remove the usage of the found method
Add a definition for the method in the appropriate parent
Fix the name of the method, and replace it with a valid definition
Change ‘parent’ with ‘self’ if the method is eventually defined in the current class
Change ‘parent’ with another object, if the method has been defined in another class
Add the ‘extends’ keyword to the class, to actually have a parent class
1.2.186.2. Specs¶
Short name |
Classes/UndefinedParentMP |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.187. Undefined Properties¶
List of properties that are not explicitly defined in the class, its parents or traits.
<?php
class foo {
// property definition
private bar = 2;
function foofoo() {
// $this->bar is defined in the class
// $this->barbar is NOT defined in the class
return $this->bar + $this->barbar;
}
}
?>
It is possible to spot unidentified properties by using the PHP’s magic methods __get and __set. Even if the class doesn’t use magic methods, any call to an undefined property will be directed to those methods, and they can be used as a canary, warning that the code is missing a definition.
<?php
trait NoUnefinedProperties {
function __get($name) {
assert(false, "Attempt to read the $name property, on the class ".__CLASS__;
}
function __set($name, $value) {
assert(false, "Attempt to read the $name property, on the class ".__CLASS__;
}
}
?>
See also Properties.
1.2.187.1. Suggestions¶
Add an explicit property definition, and give it
nullas a default value : this way, it behaves the same as undefined.Rename the property to one that exists already.
1.2.187.2. Specs¶
Short name |
Classes/UndefinedProperty |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
ClearPHP |
|
Examples |
|
Available in |
1.2.188. Undefined static:: Or self::¶
<?php
class x {
static public function definedStatic() {}
private definedStatic = 1;
public function method() {
self::definedStatic();
self::undefinedStatic();
static::definedStatic;
static::undefinedStatic;
}
}
?>
See also Late `Static Bindings <https://www.php.net/manual/en/language.oop5.late-static-bindings.php>`_.
1.2.188.1. Suggestions¶
Define the missing method or property
Remove usage of that undefined method or property
Fix name to call an actual local structure
1.2.188.2. Specs¶
Short name |
Classes/UndefinedStaticMP |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.189. Undefined ::class¶
\:\:classdoesn’t check if a corresponding class exists.
\:\:class must be checked with a call to class_exists(). Otherwise, it may lead to a Class 'foo' not found or even silent dead code : this happens also with Catch and instanceof commands with undefined classes. PHP doesn’t raise an error in that case.
<?php
class foo() {}
// prints foo
echo foo::class;
// prints bar though bar doesn't exist.
echo bar::class;
?>
See also Class Constants.
1.2.189.1. Specs¶
Short name |
Classes/UndefinedStaticclass |
Rulesets |
|
Exakat since |
1.3.5 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.190. Uninitialized Property¶
Uninitialized properties are not fully bootstrapped at the end of the constructor.
Properties may be inited at definition time, along with their visibility and type. Some types are not inited at definition time, as any object, so they should be inited during constructor. At the end of the former, all properties shall have a legit value, and be ready for usage.
<?php
class x {
private $foo = null;
private $uninited;
function __construct($arg) {
$this->foo = $args;
// $this->uninited is not inited, nor at definition, nor in constructor
// it will hold null at the beginning of the next method call
}
}
?>
1.2.190.1. Suggestions¶
Remove the property, and move it to another class
Add an initialisation for this property
1.2.190.2. Specs¶
Short name |
Classes/UninitedProperty |
Rulesets |
|
Exakat since |
2.0.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Medium |
Available in |
1.2.191. Unitialized Properties¶
Properties that are not initialized in the constructor, nor at definition.
<?php
class X {
private $i1 = 1, $i2;
protected $u1, $u2;
function __construct() {
$this->i2 = 1 + $this->u2;
}
function m() {
echo $this->i1, $this->i2, $this->u1, $this->u2;
}
}
?>
With the above class, when m() is accessed right after instantiation, there will be a missing property. Using default values at property definition, or setting default values in the constructor ensures that the created object is consistent.
1.2.191.1. Suggestions¶
Add an explicit initialization for each property.
1.2.191.2. Specs¶
Short name |
Classes/UnitializedProperties |
Rulesets |
|
Exakat since |
0.8.9 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.192. Unreachable Class Constant¶
Class constants may be unreachable due to visibility configuration.
Since PHP 7.1, class constants support visibility. Their usage may be restricted to the current class, or private, to classes that extends or are extended by the current class, or protected. They may also be public, just like it was before.
<?php
class Foo{
private const PRIVATE = 1;
const PUBLIC = 3;
}
// PHP 7.1- and older
echo Foo::PUBLIC;
// This is not accessible
echo Foo::PRIVATE;
?>
See also Class Constant and PHP RFC: Support Class Constant Visibility.
1.2.192.1. Suggestions¶
Make the class constant protected, when the call to the constant is inside a related class.
Create another constant, that may be accessible
Make the class constant public
1.2.192.2. Specs¶
Short name |
Classes/UnreachableConstant |
Rulesets |
|
Exakat since |
1.5.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.193. Unresolved Catch¶
Catch clauses do not check for Exception existence.
Catch clauses check that the emitted expression is of the requested Class, but if that class doesn’t exist in the code, the catch clause is always false. This is dead code.
<?php
try {
// doSomething()
} catch {TypoedExxeption $e) { // Do not exist Exception
// Fix this exception
} catch {Stdclass $e) { // Exists, but is not an exception
// Fix this exception
} catch {Exception $e) { // Actual and effective catch
// Fix this exception
}
?>
1.2.193.1. Suggestions¶
Fix the name of the exception
Remove the catch clause
Add a use expression with a valid name
Create/import the missing exception
See also PHP Try Catch: Basics & Advanced PHP Exception Handling Tutorial and Silent failure to catch exceptions in PHP.
1.2.193.2. Specs¶
Short name |
Classes/UnresolvedCatch |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
ClearPHP |
|
Available in |
1.2.194. Unresolved Classes¶
The following classes are instantiated in the code, but their definition couldn’t be found.
<?php
class Foo extends Bar {
private function foobar() {
// here, parent is not resolved, as Bar is not defined in the code.
return parent::$prop;
}
}
?>
1.2.194.1. Suggestions¶
Check for namespaces and aliases and make sure they are correctly configured.
1.2.194.2. Specs¶
Short name |
Classes/UnresolvedClasses |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.195. Unresolved Instanceof¶
The instanceof operator doesn’t confirm if the compared class exists.
It checks if an variable is of a specific class. However, if the referenced class doesn’t exist, because of a bug, a missed inclusion or a typo, the operator always fails, without a warning.
<?php
namespace X {
class C {}
// This is OK, as C is defined in X
if ($o instanceof C) { }
// This is not OK, as C is not defined in global
// instanceof respects namespaces and use expressions
if ($o instanceof \C) { }
// This is not OK, as undefinedClass
if ($o instanceof undefinedClass) { }
// This is not OK, as $class is now a full namespace. It actually refers to \c, which doesn't exist
$class = 'C';
if ($o instanceof $class) { }
}
?>
Make sure the following classes are well defined.
See also Instanceof.
1.2.195.1. Suggestions¶
Remove the call to instanceof and all its dependencies.
Fix the class name and use a class existing in the project.
1.2.195.2. Specs¶
Short name |
Classes/UnresolvedInstanceof |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Instant (5 mins) |
Precision |
High |
ClearPHP |
|
Examples |
|
Available in |
1.2.196. Unused Classes¶
The following classes are never explicitly used in the code.
Note that this may be valid in case the current code is a library or framework, since it defines classes that are used by other (unprovided) codes. Also, this analyzer may find classes that are, in fact, dynamically loaded.
<?php
class unusedClasss {}
class usedClass {}
$y = new usedClass();
?>
1.2.196.1. Suggestions¶
Remove unused classes
Make use of unused classes
Fix class name
1.2.196.2. Specs¶
Short name |
Classes/UnusedClass |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.197. Unused Class Constant¶
The class constant is unused. Consider removing it.
<?php
class foo {
public const UNUSED = 1; // No mention in the code
private const USED = 2; // used constant
function bar() {
echo self::USED;
}
}
?>
1.2.197.1. Suggestions¶
Remove the class constant
Use the class constant
1.2.197.2. Specs¶
Short name |
Classes/UnusedConstant |
Rulesets |
|
Exakat since |
1.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.198. Unused Methods¶
Those methods are never called.
They are probably dead code, unless they are called dynamically.
This analysis omits methods which are in a class that makes dynamical self calls : $this->$m(). That way, any method may be called.
This analysis omits methods which are overwritten by a child class. That way, they are considered to provide a default behavior.
<?php
class foo {
public function used() {
$this->used();
}
public function unused() {
$this->used();
}
}
class bar extends foo {
public function some() {
$this->used();
}
}
$a = new foo();
$a->used();
?>
See also Dead Code: Unused Method.
1.2.198.1. Suggestions¶
Make use of the method
Remove the method
Move the method to another class
1.2.198.2. Specs¶
Short name |
Classes/UnusedMethods |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.199. Unused Private Methods¶
Private methods that are not used in the local class are dead code. Protected methods that are not used in the local class or its children, are dead code.
Private methods are reserved for the defining class. Thus, they must be used with the current class, with $this or self\:\:.
Protected methods, in a standalone class, are also included.
<?php
class Foo {
// Those methods are used
private function method() {}
private static function staticMethod() {}
// Those methods are not used
private function unusedMethod() {}
private static function staticUnusedMethod() {}
public function bar() {
self::staticMethod();
$this->method();
}
}
?>
This analysis skips classes that makes self dynamic calls, such as $this->$method().
1.2.199.1. Suggestions¶
Remove the private method, as it is unused
Add a call to this private method
Change method visibility to make it available to other classes
1.2.199.2. Specs¶
Short name |
Classes/UnusedPrivateMethod |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Available in |
1.2.200. Unused Private Properties¶
Unused static properties should be removed.
Unused private properties are dead code. They are usually leftovers of development or refactorisation : they used to have a mission, but are now left.
Being private, those properties are only accessible to the current class or trait. As such, validating the
<?php
class foo {
// This is a used property (see bar method)
private $used = 1;
// This is an unused property
private $unused = 2;
function bar($a) {
$this->used += $a;
return $this->used;
}
}
?>
1.2.200.1. Suggestions¶
Remove the property altogether
Check if the property wasn’t forgotten in the rest of the class
Check if the property is correctly named
Change the visibility to protected or public : may be a visibility refactoring was too harsh
1.2.200.2. Specs¶
Short name |
Classes/UnusedPrivateProperty |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.201. Unused Protected Methods¶
The following protected methods are unused in children class. As such, they may be considered for being private.
Methods reported by this analysis are not used by children, yet they are protected.
<?php
class Foo {
// This method is not used
protected function unusedBar() {}
protected function usedInFoo() {}
protected function usedInFooFoo() {}
public function bar2() {
// some code
$this->usedInFoo();
}
}
class FooFoo extends Foo {
protected function bar() {}
public function bar2() {
// some code
$this->usedInFooFoo();
}
}
class someOtherClass {
protected function bar() {
// This is not related to foo.
$this->unusedbar();
}
}
?>
No usage of those methods were found.
This analysis is impacted by dynamic method calls.
1.2.201.1. Suggestions¶
Make use of the protected method in the code
Remove the method
1.2.201.2. Specs¶
Short name |
Classes/UnusedProtectedMethods |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.202. Use ::Class Operator¶
Use
\:\:classto hardcode class names, instead of strings.
This is actually faster than strings, which are parsed at execution time, while \:\:class is compiled, making it faster to execute.
\:\:class operator is also able to handle use expressions, including aliases and local namespace. The code is easier to maintain. For example, the target class’s namespace may be renamed, without changing the \:\:class, while the string must be updated.
\:\:class operator works with self and ``static``keywords.
<?php
namespace foo\bar;
use foo\bar\X as B;
class X {}
$className = '\foo\bar\X';
$className = foo\bar\X::class;
$className = B\X;
$object = new $className;
?>
This is not possible when building the name of the class with concatenation.
This is a micro-optimization. This also helps static analysis, as it gives more information at compile time to analyse.
See also ::class.
1.2.202.1. Suggestions¶
Replace strings by the ::class operator whenever possible
1.2.202.2. Specs¶
Short name |
Classes/UseClassOperator |
Rulesets |
|
Exakat since |
0.8.7 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
Medium |
Examples |
|
Available in |
1.2.203. Use Instanceof¶
The
instanceofoperator is a more precise alternative tois_object(). It is also faster.
instanceof checks for an variable to be of a class or its parents or the interfaces it implements.
Once instanceof has been used, the actual attributes available (properties, constants, methods) are known, unlike with is_object().
Last, instanceof may be upgraded to Typehint, by moving it to the method signature.
<?php
class Foo {
// Don't use is_object
public function bar($o) {
if (!is_object($o)) { return false; } // Classic argument check
return $o->method();
}
// use instanceof
public function bar($o) {
if ($o instanceof myClass) { // Now, we know which methods are available
return $o->method();
}
return false; } // Default behavior
}
// use of typehinting
// in case $o is not of the right type, exception is raised automatically
public function bar(myClass $o) {
return $o->method();
}
}
?>
instanceof and is_object() may not be always interchangeable. Consider using isset() on a known property for a simple check on objects. You may also consider is_string(), is_integer() or is_scalar(), in particular instead of !`is_object() <https://www.php.net/is_object>`_.
The instanceof operator is also faster than the is_object() functioncall.
See also Type Operators and is_object.
1.2.203.1. Suggestions¶
Use instanceof and remove is_object()
Create a high level interface to check a whole family of classes, instead of testing them individually
Use typehint when possible
Avoid mixing scalar types and objects in the same variable
1.2.203.2. Specs¶
Short name |
Classes/UseInstanceof |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.204. Use This¶
A method that doesn’t use any local data may be considered for a move : may be this doesn’t belong here.
The following functioncalls have been added, as access to the current class, without using $this or self :
get_class( )
get_called_class( )
get_object_vars( )
get_parent_class( )
get_class_vars( )
get_class_methods( )
<?php
class dog {
private $name = 'Rex';
// This method is related to the current object and class
public function attaboy() {
return Fetch, $this->name, Fetch\n;
}
// Not using any class related data : Does this belong here?
public function addition($a, $b) {
return $a + $b;
}
}
?>
See also The Basics.
1.2.204.1. Specs¶
Short name |
Classes/UseThis |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.205. Used Classes¶
The following classes are used in the code.
Classes may be use when they are instantiated, or with static calls
<?php
class unusedClasss { const X = 1;}
class usedClass {}
$y = new usedClass(usedClass::X);
?>
1.2.205.1. Specs¶
Short name |
Classes/UsedClass |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.206. Used Methods¶
Those methods are used in the code. This analysis is mostly useful for its contrary.
<?php
class foo {
public function used() {
$this->used();
}
// No usage of 'unused', as method call, in or out of the definition class.
public function unused() {
$this->used();
}
}
class bar extends foo {
public function some() {
$this->used();
}
}
$a = new foo();
$a->used();
?>
1.2.206.1. Specs¶
Short name |
Classes/UsedMethods |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.207. Used Once Property¶
Property used once in their defining class.
Properties used in one method only may be used several times, and read only. This may be a class constant. Such properties are meant to be overwritten by an extending class, and that’s possible with class constants.
Setting properties with default values is a good way to avoid littering the code with literal values, and provide a single point of update (by extension, or by hardcoding) for all those situations. A constant is definitely better suited for this task.
<?php
class foo {
private $defaultCols = '*';
cont DEFAULT_COLUMNS = '*';
// $this->defaultCols holds a default value. Should be a constant.
function bar($table, $cols) {
// This is necessary to activate usage of default values
if (empty($cols)) {
$cols = $this->defaultCols;
}
$res = $this->query('SELECT '.$cols.' FROM '.$table);
// ....
}
// Upgraded version of bar, with default values
function bar2($table, $cols = self::DEFAULT_COLUMNS) {
$res = $this->query('SELECT '.$cols.' FROM '.$table);
// .....
}
}
?>
1.2.207.1. Suggestions¶
Remove the property, as it is probably not unused
Add another usage of the property where it is useful
1.2.207.2. Specs¶
Short name |
Classes/UsedOnceProperty |
Rulesets |
|
Exakat since |
0.10.3 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.208. Used Private Methods¶
List of all private methods that are used.
Protected methods, in a standalone class, are also included.
<?php
class Foo {
// Those methods are used
private function method() {}
private static function staticMethod() {}
// Those methods are not used
private function unusedMethod() {}
private static function staticUnusedMethod() {}
public function bar() {
self::staticMethod();
$this->method();
}
}
?>
1.2.208.1. Specs¶
Short name |
Classes/UsedPrivateMethod |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.209. Used Static Properties¶
List of all static properties that are used.
A private property is used when it is defined and read. A private property that is only written is not used. A property that is only read is used, as it may have a default value, or act as NULL.
<?php
class foo {
// This is a used property (see bar method)
private $used = 1;
function bar($a) {
$this->used += $a;
return $this->used;
}
}
?>
See also and .
1.2.209.1. Specs¶
Short name |
Classes/UsedPrivateProperty |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.210. Used Protected Method¶
Marks methods being used in the current class or its children classes.
<?php
class foo {
// This is reported
protected usedByChildren() {}
// This is not reported
protected notUsedByChildren() {}
}
class bar extends foo {
// The parent method is not overloaded, though it may be
protected someMethod() {
// The parent method is called
$this->usedByChildren();
}
}
?>
See also Visibility.
1.2.210.1. Specs¶
Short name |
Classes/UsedProtectedMethod |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.211. Useless Abstract Class¶
Those classes are marked ‘abstract’ and they are never extended. This way, they won’t be instantiated nor used.
Abstract classes that have only static methods are omitted here : one usage of such classes are Utilities classes, which only offer static methods.
<?php
// Never extended class : this is useless
abstract class foo {}
// Extended class
abstract class bar {
public function barbar() {}
}
class bar2 extends bar {}
// Utility class : omitted here
abstract class bar {
public static function barbar() {}
}
?>
1.2.211.1. Suggestions¶
Drop the abstract keyword
Actually add an abstract keyword
1.2.211.2. Specs¶
Short name |
Classes/UselessAbstract |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.212. Useless Constructor¶
Class constructor that have empty bodies are useless. They may be removed.
<?php
class X {
function __construct() {
// Do nothing
}
}
class Y extends X {
// Useful constructor, as it prevents usage of the parent
function __construct() {
// Do nothing
}
}
?>
1.2.212.1. Specs¶
Short name |
Classes/UselessConstructor |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.213. Useless Final¶
When a class is declared final, all of its methods are also final by default.
There is no need to declare them individually final.
<?php
final class foo {
// Useless final, as the whole class is final
final function method() { }
}
class bar {
// Useful final, as the whole class is not final
final function method() { }
}
?>
See also Final Keyword, and When to declare final.
1.2.213.1. Specs¶
Short name |
Classes/UselessFinal |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
ClearPHP |
|
Available in |
1.2.214. Useless Typehint¶
<?php
class x {
// typehint is set and ignored
function __set(float $name, string $value) {
$this->$name = $value;
}
// typehint is set and ignored
function __get(integer $name) {
$this->$name = $value;
}
// typehint is checked by PHP 8.0 linting
// typehint is enforced by PHP 7.x
function __call(integer $name) {
$this->$name = $value;
}
}
$o = new x;
$b = array();
// Property will be called 'Array'
$o->{$b} = 2;
// type of $m is check at calling time. It must be string.
$o->{$m}();
?>
See also __set.
1.2.214.1. Suggestions¶
Use string for the $name parameter
Use no typehint for the $name parameter
1.2.214.2. Specs¶
Short name |
Classes/UselessTypehint |
Rulesets |
|
Exakat since |
2.1.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Available in |
1.2.215. Using $this Outside A Class¶
$thisis a special variable, that should only be used in a class context.
Until PHP 7.1, $this may be used as an argument in a function or a method, a global, a static : while this is legit, it sounds confusing enough to avoid it.
<?php
function foo($this) {
echo $this;
}
// A closure can be bound to an object at later time. It is valid usage.
$closure = function ($x) {
echo $this->foo($x);
}
?>
Starting with PHP 7.1, the PHP engine check thoroughly that $this is used in an appropriate manner, and raise fatal errors in case it isn’t.
Yet, it is possible to find $this outside a class : if the file is included inside a class, then $this will be recognized and validated. If the file is included outside a class context, it will yield a fatal error : Using `$this <https://www.php.net/manual/en/language.oop5.basic.php>`_ when not in object context.
See also Closure::bind and The Basics.
1.2.215.1. Specs¶
Short name |
Classes/UsingThisOutsideAClass |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
With PHP 7.0 and older |
Severity |
Critical |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.216. Dynamically Called Classes¶
Indicates if a class is called dynamically.
<?php
// This class is called dynamically
class X {
const CONSTANTE = 1;
}
$classe = 'X';
$x = new $classe();
echo $x::CONSTANTE;
?>
1.2.216.1. Specs¶
Short name |
Classes/VariableClasses |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.217. Weak Typing¶
The test on a variable is not enough. The variable is checked for null, then used as an object or an array.
<?php
if ($a !== null) {
echo $a->b;
}
?>
See also From assumptions to assertions.
1.2.217.1. Suggestions¶
Use instanceof when checking for objects
Use is_array() when checking for arrays. Also consider is_string(), is_int(), etc.
Use typehint when the variable is an argument
1.2.217.2. Specs¶
Short name |
Classes/WeakType |
Rulesets |
|
Exakat since |
1.2.8 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.218. Wrong Class Name Case¶
The spotted classes are used with a different case than their definition. While PHP accepts this, it makes the code harder to read.
It may also be a violation of coding conventions.
<?php
// This use statement has wrong case for origin.
use Foo as X;
// Definition of the class
class foo {}
// Those instantiations have wrong case
new FOO();
new X();
?>
See also PHP class name constant case sensitivity and PSR-11.
1.2.218.1. Suggestions¶
Match the defined class name with the called name
1.2.218.2. Specs¶
Short name |
Classes/WrongCase |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.219. Illegal Name For Method¶
PHP has reserved usage of methods starting with
__for magic methods. It is recommended to avoid using this prefix, to prevent confusions.
<?php
class foo{
// Constructor
function __construct() {}
// Constructor's typo
function __constructor() {}
// Illegal function name, even as private
private function __bar() {}
}
?>
See also Magic Methods.
1.2.219.1. Suggestions¶
Avoid method names starting with a double underscore :
__Use method visibilities to ensure that methods are only available to the current class or its children
1.2.219.2. Specs¶
Short name |
Classes/WrongName |
Rulesets |
|
Exakat since |
0.9.2 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Examples |
|
Available in |
1.2.220. Wrong Typed Property Default¶
Property is typed with an incompatible default value type.
Init type might be a new instance, the return of a method call or an interface compatible object.
<?php
class x {
private A $property;
private B $incompatible;
function __construct() {
// This is compatible
$this->property = new A();
// This is incompatible : new B() expected
$this->incompatible = new C();
}
}
?>
PHP compiles such code, but won’t execute it, as it detects the incompatibility.
1.2.220.1. Suggestions¶
Remove the type hint of the property
Fix the initialization call
Use an interface for typehint
1.2.220.2. Specs¶
Short name |
Classes/WrongTypedPropertyInit |
Rulesets |
|
Exakat since |
2.0.9 |
PHP Version |
7.4+ |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.221. Magic Visibility¶
The class magic methods must have public visibility and cannot be static.
<?php
class foo{
// magic method must bt public and non-static
public static function __clone($name) { }
// magic method can't be private
private function __get($name) { }
// magic method can't be protected
private function __set($name, $value) { }
// magic method can't be static
public static function __isset($name) { }
}
?>
See also Magic methods.
1.2.221.1. Specs¶
Short name |
Classes/toStringPss |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
5.4- |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.222. Create Compact Variables¶
This command creates Variable definitions, based on usage of ‘compact’.
<?php
function foo() {
$a = 1;
return compact('a');
}
?>
This only works when compact() is used with literal values, or with constants. Dynamic values are not reported.
1.2.222.1. Specs¶
Short name |
Complete/CreateCompactVariables |
Rulesets |
|
Exakat since |
1.9.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.223. Create Default Values¶
This commands adds a link between variables, property definitions and any assignation to this container.
Variables have no definition expression in PHP. Exakat holds their definition with the Variabledefinition node.
Properties have definitions, and non-compulsory default values. This command creates multiple DEFINITION link for them.
DEFAULT is convenient in the case of null value, which will be assigned an object at execution time.
<?php
function foo() {
// local Variabledefinition links to this expression
$a = 1;
}
class x {
// 1 is a default value
private $p = 1;
function __construct() {
// 2 is also a default value for this.
// This default value is different from the above as it is a part of an assignation
$this->p = 2;
}
}
?>
Short assignations, such as += are not considered default value. It needs to be a full assignation
1.2.223.1. Specs¶
Short name |
Complete/CreateDefaultValues |
Rulesets |
|
Exakat since |
1.9.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.224. Complete/CreateForeachDefault¶
1.2.224.1. Specs¶
Short name |
Complete/CreateForeachDefault |
Rulesets |
|
Exakat since |
1.9.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.225. Create Magic Method¶
This command creates a link DEFINITION between a
__call()and__callStatic()calls, and its equivalent magic method.
<?php
class x {
function foo() {
// This is linked to __call
$this->c();
// This is linked to __callStatic
return $this::C();
}
function __call($name, $args) {
// Normal method call
}
function __callStatic($name, $args) {
// Static method call
}
}
?>
This command may not detect all possible link for the __get() and __set() call. It may be missing information about the nature of the object. Self, static, parent and simple variables are detected.
See also Magic Methods.
1.2.225.1. Specs¶
Short name |
Complete/CreateMagicMethod |
Rulesets |
none |
Exakat since |
1.9.6 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.226. Create Magic Property¶
This command creates a link DEFINITION between a
__getand__setcalls, and its equivalent magic method.
<?php
class x {
function foo() {
// This is linked to __set
$this->a = 1;
// This is linked to __get
return $this->b;
}
function __get($name) {
return 1;
}
function __set($name, $value) {
// Store the value
}
}
?>
This command may not detect all possible link for the __get and __set call. It may be missing information about the nature of the object.
1.2.226.1. Specs¶
Short name |
Complete/CreateMagicProperty |
Rulesets |
|
Exakat since |
1.9.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.227. Extended Typehints¶
Produces all the definition links between typehints (arguments, return types, properties) and the definitions that are valid with the typehint.
<?php
function foo(A $A) {}
// This is the raw definition of the above typehint
interface A {}
// This is valid definition of the above typehint
class X implements A {}
// This is valid definition of the above typehint
class Y extends X {}
// This is not related to the typehint
class Z {}
?>
1.2.227.1. Specs¶
Short name |
Complete/ExtendedTypehints |
Rulesets |
|
Exakat since |
2.1.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.228. Follow Closure Definition¶
This command adds DEFINITION link between closure definitions and their usage.
Local usage of the closure, in the same scope, are detected. Relayed closure, when they are transmitted to another method for usage, is detected, for one level.
<?php
function foo() {
$closure = function () {};
// Local usage
echo $closure();
}
function bar(Closure $x) {
// relayed usage
echo $x();
}
?>
1.2.228.1. Specs¶
Short name |
Complete/FollowClosureDefinition |
Rulesets |
|
Exakat since |
1.9.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.229. Make Class Constant Definition¶
This command adds DEFINITION link between class constant definitions and their usage.
<?php
class x {
public const A = 1;
}
// Link to the constant definition
echo x::A;
// Cannot find the original class
echo $x::A;
?>
1.2.229.1. Specs¶
Short name |
Complete/MakeClassConstantDefinition |
Rulesets |
|
Exakat since |
1.9.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.230. Make Class Method Definition¶
This command links a method call to its method definition.
<?php
class x {
function foo() {
// This links to the bar() method
return $this->bar();
}
function bar() {
// This links to the link() method
return $this->bar();
}
}
?>
This command may not detect all possible link for the methods. It may be missing information about the nature of the object.
This command may also produce multiple definitions link, when the definition are ambiguous.
1.2.230.1. Specs¶
Short name |
Complete/MakeClassMethodDefinition |
Rulesets |
|
Exakat since |
1.9.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.231. Make Functioncall With Reference¶
Mark parameters as
isModifiedif the functioncall uses reference.
This works on PHP native functions and custom functions.
This doesn’t work on dynamic calls.
1.2.231.1. Specs¶
Short name |
Complete/MakeFunctioncallWithReference |
Rulesets |
|
Exakat since |
1.9.7 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.232. Overwritten Constant¶
This command adds OVERWRITE link between class constant definitions.
<?php
class x {
protected const A = 1;
}
class y extends x {
protected const A = 1;
}
?>
The A constant will be linked between classes x and y, with an OVERWRITE link.
1.2.232.1. Specs¶
Short name |
Complete/OverwrittenConstants |
Rulesets |
|
Exakat since |
1.9.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.233. Overwritten Methods¶
This command adds OVERWRITE link between methods definitions of classes.
<?php
class x {
protected function foo() {}
}
class y extends x {
protected function foo() {}
}
?>
The foo method will be linked between classes x and y, with an OVERWRITE link.
1.2.233.1. Specs¶
Short name |
Complete/OverwrittenMethods |
Rulesets |
|
Exakat since |
1.9.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.234. Overwritten Properties¶
This command adds OVERWRITE link between property definitions of classes.
<?php
class x {
protected $p = 1;
}
class y extends x {
protected $p = 1;
}
?>
The $p property will be linked between classes x and y, with an OVERWRITE link.
1.2.234.1. Specs¶
Short name |
Complete/OverwrittenProperties |
Rulesets |
|
Exakat since |
1.9.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.235. Complete/PhpExtStubPropertyMethod¶
Provides isExt property to method call and properties access, based on typehints and local instantiation.
1.2.235.1. Specs¶
Short name |
Complete/PhpExtStubPropertyMethod |
Rulesets |
|
Exakat since |
2.1.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.236. Complete/PhpNativeReference¶
1.2.236.1. Specs¶
Short name |
Complete/PhpNativeReference |
Rulesets |
|
Exakat since |
1.9.1 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.237. Propagate Calls¶
Update the graph, by linking a call to its definition. A call may be a function call, a closure call, a method call, a static methodcall.
Note that the definition is not always available, and the linking may fail. This is the case for PHP native functions, for dynamically build names, or omitted libraries.
1.2.237.1. Specs¶
Short name |
Complete/PropagateCalls |
Rulesets |
|
Exakat since |
1.9.8 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.238. Propagate Constants¶
This command calculates constant expression values, and set them in the graph.
<?php
const A = 1;
const B = A + 2;
?>
After running this command, B has intval of 3.
This command propagate const constants, class constants and define() constants, when possible.
1.2.238.1. Specs¶
Short name |
Complete/PropagateConstants |
Rulesets |
|
Exakat since |
1.9.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.239. SetA rray Class Definition¶
Link arrays() with their class / method definition.
PHP accepts an array structure such as [class, method], or [$object, method] as a valid method callback. This analysis build such relations, whenever they are static.
<?php
class x {
public function foo() {}
}
// designate the foo method in the x class
$f = [\x, 'foo'];
array_
?>
1.2.239.1. Specs¶
Short name |
Complete/SetArrayClassDefinition |
Rulesets |
|
Exakat since |
1.9.3 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.240. Set Class_Alias Definition¶
Links
newcalls to the concrete class when class_alias() was used to create the name. The link isDEFINITION.
class_alias() are detected at loading time, and are used unconditionally.
This means that the fully qualified name of the new call and the instantiated class may be different : without the alias, the fully qualified name is the current fullcode, or its use’s origin, while with class_alias(), it is an arbitrary name.
<?php
class x {
public function foo() {}
}
class_alias('x', 'y');
//y exists, as an alias of x.
$y = new y;
?>
1.2.240.1. Specs¶
Short name |
Complete/SetClassAliasDefinition |
Rulesets |
|
Exakat since |
1.9.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.241. Set Class Method Remote Definition¶
Links method to the method definition. The link is
DEFINITION.
Static method calls and normal method calls are both solved with this rule. Parent classes and trait are also searched for the right method.
<?php
class x {
public function __construct() {}
public function foo() {}
}
// This links to __construct method
$a = new x;
// This links to foo() method
$a->foo();
?>
1.2.241.1. Specs¶
Short name |
Complete/SetClassMethodRemoteDefinition |
Rulesets |
|
Exakat since |
1.9.3 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.242. Set Class Property Definition With Typehint¶
Links method call to its definition, thanks to property typehinting. The link is
DEFINITION.
<?php
class x {
public x $p = null;
public function bar() {
return $this;
}
}
$x = new x;
// $x->p is of 'x' class
$x->p->bar();
?>
1.2.242.1. Specs¶
Short name |
Complete/SetClassPropertyDefinitionWithTypehint |
Rulesets |
|
Exakat since |
1.9.3 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.243. Set Class Remote Definition With Global¶
Links method call to its definition, thanks to the global definition. The link is
DEFINITION.
<?php
class x {
public function bar() { }
}
global $a;
$a = new X;
function foo() {
global $a;
// This links to class x, method bar(), thanks to global.
return $a->bar();
}
?>
1.2.243.1. Specs¶
Short name |
Complete/SetClassRemoteDefinitionWithGlobal |
Rulesets |
|
Exakat since |
1.9.3 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.244. Complete/SetClassRemoteDefinitionWithInjection¶
1.2.244.1. Specs¶
Short name |
Complete/SetClassRemoteDefinitionWithInjection |
Rulesets |
|
Exakat since |
1.9.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.245. Set Class Remote Definition With Local New¶
Links method calls and properties to its definition, thanks to the local new. The link is
DEFINITION.
<?php
class x {
public function bar() { }
}
function foo() {
$a = new x;
// This links to class x, method bar(), thanks to the local new.
return $a->bar();
}
?>
1.2.245.1. Specs¶
Short name |
Complete/SetClassRemoteDefinitionWithLocalNew |
Rulesets |
|
Exakat since |
1.9.3 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.246. Complete/SetClassRemoteDefinitionWithParenthesis¶
Links method call to its definition, thanks to the new in parenthesis. The link is
DEFINITION.
<?php
class x {
public function bar() { }
}
function foo() {
// This links to class x, method bar(), thanks to the new.
return (new x)->bar();
}
?>
1.2.246.1. Specs¶
Short name |
Complete/SetClassRemoteDefinitionWithParenthesis |
Rulesets |
|
Exakat since |
1.9.3 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.247. Set Class Remote Definition With Return Typehint¶
Links method call to its definition, thanks to the typed return. The link is
DEFINITION.
<?php
class x {
public function bar() { }
}
function foo() {
$a = bar();
// This links to class x, method bar(), thanks to the new.
return $a->bar();
}
function bar() : x {
return new x;
}
?>
1.2.247.1. Specs¶
Short name |
Complete/SetClassRemoteDefinitionWithReturnTypehint |
Rulesets |
|
Exakat since |
1.9.3 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.248. Complete/SetClassRemoteDefinitionWithTypehint¶
Links method call to its definition, thanks to the typed argument. The link is
DEFINITION.
<?php
class x {
public function bar() { }
}
function foo(x $a) {
// This links to class x, method bar(), thanks to the typehint.
return $a->bar();
}
?>
1.2.248.1. Specs¶
Short name |
Complete/SetClassRemoteDefinitionWithTypehint |
Rulesets |
|
Exakat since |
1.9.3 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.249. Set Clone Link¶
This command creates a link DEFINITION between a clone call, and its equivalent magic method.
<?php
class x {
// Store an object
private $a;
function foo() {
// This clone is linked to the magic method below
return clone $this;
}
function __clone() {
$this->a = clone $this->a;
}
}
// This is not linked to any __clone method, by lack of information
clone $x;
?>
This command may not detect all possible link for the clone. It may be missing information about the nature of the clone object.
1.2.249.1. Specs¶
Short name |
Complete/SetCloneLink |
Rulesets |
|
Exakat since |
1.9.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.250. Set Parent Definition¶
This command creates a DEFINITION link between parent keyword and the actual parent class.
<?php
class x {
const A = 1;
}
class y extends x {
function foo() {
// 'parent' needs a DEFFINITION link to the class x
return parent::A;
}
}
?>
1.2.250.1. Specs¶
Short name |
Complete/SetParentDefinition |
Rulesets |
|
Exakat since |
1.9.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.251. Set String Method Definition¶
Links a string with a static method call to its definition. The link is
DEFINITION.
<?php
class B {
static public function C() {}
}
$a = 'B::C';
?>
1.2.251.1. Specs¶
Short name |
Complete/SetStringMethodDefinition |
Rulesets |
|
Exakat since |
1.9.3 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.252. Solve Trait Methods¶
This command adds DEFINITION link between trait’s method definitions and their usage in classes.
<?php
trait t {
function foo() {
}
}
class x {
use t { t::foo as foo2; };
function bar() {
// Link to foo() in trait t
$this->foo();
// Link to foo() in trait t, thanks to 'as'
$this->foo2();
}
}
?>
1.2.252.1. Specs¶
Short name |
Complete/SolveTraitMethods |
Rulesets |
|
Exakat since |
1.9.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.253. Composer’s autoload¶
Is this code using the autoload from Composer.
1.2.253.1. Specs¶
Short name |
Composer/Autoload |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.254. Is Composer Class¶
Mark a class as part of Composer’s library.
1.2.254.1. Specs¶
Short name |
Composer/IsComposerClass |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.255. Is Composer Interface¶
Mark interfaces as Composer interfaces.
1.2.255.1. Specs¶
Short name |
Composer/IsComposerInterface |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.256. Composer Namespace¶
Mark this namespace as a Composer namespace.
When the namespace is found in the composer database, it is marked as such.
<?php
namespace Monolog;
use Monolog\Processor\WebProcessor;
use Monolog\Handler\TestHandler;
class MyLogger extends WebProcessor {
/**/
}
?>
See also Packagist.
1.2.256.1. Specs¶
Short name |
Composer/IsComposerNsname |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.257. Composer Usage¶
Mark the usage of composer, mostly by having a
composer.jsonfile.
1.2.257.1. Specs¶
Short name |
Composer/UseComposer |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.258. Use Composer Lock¶
Reports if
composer.lockwas committed to the archive.
1.2.258.1. Specs¶
Short name |
Composer/UseComposerLock |
Rulesets |
|
Exakat since |
0.9.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.259. Bad Constants Names¶
PHP’s manual recommends that developer do not use constants with the convention
__NAME__. Those are reserved for PHP future use.
For example, __TRAIT__ recently appeared in PHP, as a magic constant. In the future, other may appear.
<?php
const __MY_APP_CONST__ = 1;
const __MY_APP_CONST__ = 1;
define('__MY_OTHER_APP_CONST__', 2);
?>
The analyzer will report any constant which name is __.*.__, or even _.*_ (only one underscore).
See also Constants.
1.2.259.1. Suggestions¶
Avoid using names that doesn’t comply with PHP’s convention
1.2.259.2. Specs¶
Short name |
Constants/BadConstantnames |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Examples |
|
Available in |
1.2.260. Case Insensitive Constants¶
PHP constants may be case insensitive, when defined with define() and the third argument.
This feature is deprecated since PHP 7.3 and will be removed in PHP 8.0.
<?php
// case sensitive
define('A', 1);
// case insensitive
define('B', 1, true);
echo A;
// This is not possible
//echo a;
// both possible
echo B;
echo b;
?>
See also define.
1.2.260.1. Specs¶
Short name |
Constants/CaseInsensitiveConstants |
Rulesets |
|
Exakat since |
1.3.9 |
PHP Version |
All |
PHP deprecated |
From PHP 7.3 to 7.4 |
Severity |
Critical |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.261. Conditioned Constants¶
Indicates if a constant will be defined only if a condition is met.
<?php
if (time() > 1519629617) {
define('MY_CONST', false);
} else {
define('MY_CONST', time() - 1519629617);
}
?>
1.2.261.1. Specs¶
Short name |
Constants/ConditionedConstants |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.262. Const Or Define Preference¶
Constand define() have almost the same functional use : they create constants.
The analyzed code has less than 10% of one of them : for consistency reasons, it is recommended to make constant definition consistent.
It is recommended to use const for global constants, as this keyword is processed at compile time, while define() is executed.
Note that define() used to allow the creation of case-insensitive constants, but this is deprecated since PHP 7.3 and will be removed in PHP 8.0.
<?php
define('A1', 1);
define('A2', 1);
define('A3', 1);
define('A4', 1);
define('A5', 1);
define('A6', 1);
define('A7', 1);
define('A8', 1);
define('A9', 1);
define('A10',1);
const B = 3;
?>
See also Constant definition and Define.
1.2.262.1. Specs¶
Short name |
Constants/ConstDefinePreference |
Rulesets |
|
Exakat since |
1.3.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.263. Use const¶
The const keyword may be used to define constant, just like the define() function.
When defining a constant, it is recommended to use ‘const’ when the features of the constant are not dynamical (name or value are known at compile time). This way, constant will be defined at compile time, and not at execution time.
<?php
//Do
const A = 1;
// Don't
define('A', 1);
?>
define() function is useful when the constant is not known at compile time, or when case sensitivity is necessary.
<?php
// Read $a in database or config file
define('A', $a);
// Read $a in database or config file
define('B', 1, true);
echo b;
?>
See also Syntax.
1.2.263.1. Suggestions¶
Use const instead of define()
1.2.263.2. Specs¶
Short name |
Constants/ConstRecommended |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Examples |
|
Available in |
1.2.264. Constants With Strange Names¶
List of constants being defined with names that are incompatible with PHP standards.
<?php
// Define a valid PHP constant
define('ABC', 1);
const ABCD = 2;
// Define an invalid PHP constant
define('ABC!', 1);
echo defined('ABC!') ? constant('ABC!') : 'Undefined';
// Const doesn't allow illegal names
?>
See also PHP Constants.
1.2.264.1. Suggestions¶
Rename constants to be valid constants
Adopt a naming conversion scheme, to translate names from an incompatible source to PHP’s standard (and back).
1.2.264.2. Specs¶
Short name |
Constants/ConstantStrangeNames |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.265. Constants Usage¶
List of constants being used.
<?php
const MY_CONST = 'Hello';
// PHP_EOL (native PHP Constant)
// MY_CONST (custom constant)
echo PHP_EOL . MY_CONST;
?>
1.2.265.1. Specs¶
Short name |
Constants/ConstantUsage |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.266. Constants Names¶
List of PHP constants being defined.
<?php
// with const
const X = 1;
// with define()
define ('Y', 2);
?>
1.2.266.1. Specs¶
Short name |
Constants/Constantnames |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.267. Could Be Constant¶
Literals may be replaced by an existing constant.
Constants makes the code easier to read, as they may bear a meaningful name. They also hide implementation values, with a readable name, such as const READABLE= true;. Later, upgrading constant values is easier than scouring the code with a new literal.
Not all literal can be replaced by a constant values : sometimes, literal may have the same literal value, but different meanings. Check with your application semantics before changing any literal with a constant.
<?php
const A = 'abc';
define('B', 'ab');
class foo {
const X = 'abcd';
}
// Could be replaced by B;
$a = 'ab';
// Could be replaced by A;
$a = 'abc';
// Could be replaced by foo::X;
$a = 'abcd';
?>
This analysis currently doesn’t support arrays.
This analysis also skips very common values, such as boolean, 0 and 1. This prevents too many false positive.
1.2.267.1. Suggestions¶
Turn the literal into an existing constant
1.2.267.2. Specs¶
Short name |
Constants/CouldBeConstant |
Rulesets |
|
Exakat since |
1.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.268. Constants Created Outside Its Namespace¶
Constants Created Outside Its Namespace.
Using the define() function, it is possible to create constant outside their namespace, but using the fully qualified namespace.
<?php
namespace A\B {
// define A\B\C as 1
define('C', 1);
}
namespace D\E {
// define A\B\C as 1, while outside the A\B namespace
define('A\B\C', 1);
}
?>
However, this makes the code confusing and difficult to debug. It is recommended to move the constant definition to its namespace.
1.2.268.1. Specs¶
Short name |
Constants/CreatedOutsideItsNamespace |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.269. Custom Constant Usage¶
Using constants that were not defined in PHP extensions or PHP itself.
<?php
// display MY_CONSTANT : MY_CONSTANT is a user constant.
echo MY_CONSTANT;
// display PHP version : PHP_VERSION is a native PHP constant.
echo PHP_VERSION;
// MY_CONSTANT definition.
const MY_CONSTANT;
?>
See also PHP Constants.
1.2.269.1. Specs¶
Short name |
Constants/CustomConstantUsage |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.270. Constant Case Preference¶
Define() creates constants which are case sensitive or not.
The analyzed code has less than 10% of one of them : for consistency reasons, it is recommended to make constant sentivity definition consistent.
Note that define() used to allow the creation of case-sensitive constants, but this is deprecated since PHP 7.3 and will be removed in PHP 8.0.
<?php
define('A1', 1);
define('A2', 1);
define('A3', 1);
define('A4', 1);
define('A5', 1);
define('A6', 1);
define('A7', 1);
define('A8', 1);
define('A9', 1);
define('A10',1);
define('A10',1, true);
?>
See also Constant definition.
1.2.270.1. Specs¶
Short name |
Constants/DefineInsensitivePreference |
Rulesets |
|
Exakat since |
1.3.8 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.271. Constant Dynamic Creation¶
Dynamic constants are not possible with the const keyword, though static constant expression allows for a good range of combinations, including conditions.
<?php
$a = range(0, 4);
foreach($array as $i) {
define(A$i, $i);
define(N$i, true);
}
define(C, 5);
?>
1.2.271.1. Specs¶
Short name |
Constants/DynamicCreation |
Rulesets |
|
Exakat since |
1.6.7 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.272. True False Inconsistant Case¶
TRUE or true or True is the favorite.
Usually, PHP projects choose between ALL CAPS True/False, or all lowercase True/False. Sometimes, the project will have no recommendations.
When your project use a vast majority of one of the convention, then the analyzer will report all remaining inconsistently cased constant.
<?php
$a1 = true;
$a2 = true;
$a3 = true;
$a4 = true;
$a5 = true;
$a6 = true;
$a7 = true;
$a8 = true;
$a9 = true;
$a10 = true;
// This convention is inconsistence with the rest
$b1 = TRUE;
?>
1.2.272.1. Specs¶
Short name |
Constants/InconsistantCase |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.273. Invalid Constant Name¶
There is a naming convention for PHP constants names.
According to PHP’s manual, constant names, ‘ A valid constant name starts with a letter or underscore, followed by any number of letters, numbers, or underscores.’.
Constant, must follow this regex : /[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/.
In particular when defined using define() function, no error is produced. When using const, on the other hand, the
<?php
define('+3', 1); // wrong constant!
echo constant('+3'); // invalid constant access
?>
See also Constants.
1.2.273.1. Suggestions¶
Change constant name
1.2.273.2. Specs¶
Short name |
Constants/InvalidName |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.274. Is An Extension Constant¶
Mark a constant if it belongs to a known extension.
<?php
// JSON_HEX_AMP is a constant from ext/json
echo json_encode($object, JSON_HEX_AMP);
// JSON_HEX_AMP is a constant from ext/json
echo json_encode($object, JSON_HOAX_AMP);
?>
See also Supported PHP Extensions.
1.2.274.1. Specs¶
Short name |
Constants/IsExtConstant |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.275. Is Global Constant¶
Mark a constant that may fallback to a global const definition, even though it is in a namespace.
This analysis skips PHP and ext’s functions, namespaced constants.
<?php
namespace X {
const PHP_VERSION = 1;
// Local constant
echo PHP_VERSION;
// This constant fallsback to \E_ALL, unless DNS_NS is defined in this namespace
echo E_ALL;
// This constant is always \DNS_NS
echo \DNS_NS;
// This is a Notice
echo UNDEFINED_CONSTANT;
}
?>
See also $GLOBALS and Variable scope.
1.2.275.1. Specs¶
Short name |
Constants/IsGlobalConstant |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.276. Is PHP Constant¶
Mark a constant if it is a PHP constant.
<?php
// This is an PHP constant
$a = HTML_ENTITIES;
// This is an PHP function
$a = CMS_ORDER;
?>
1.2.276.1. Specs¶
Short name |
Constants/IsPhpConstant |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.277. Magic Constant Usage¶
There are eight magical constants that change depending on where they are used. For example, the value of
__LINE__depends on the line that it’s used on in your script. These special constants are case-insensitive.
__LINE____FILE____DIR____FUNCTION____CLASS____TRAIT____METHOD____NAMESPACE__
<?php
echo 'This code is in file '__FILE__.', line '.__LINE__;
?>
See also and Magic Constants.
1.2.277.1. Specs¶
Short name |
Constants/MagicConstantUsage |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
Very high |
Available in |
1.2.278. Multiple Constant Definition¶
Some constants are defined several times in your code. This will lead to a fatal error, if they are defined during the same execution.
Multiple definitions may happens at bootstrap, when the application code is collecting information about the current environment. It may also happen at inclusion time, which one set of constant being loaded, while other definition are not, avoiding conflict. Both are false positive.
<?php
// OS is defined twice.
if (PHP_OS == 'Windows') {
define('OS', 'Win');
} else {
define('OS', 'Other');
}
?>
1.2.278.1. Suggestions¶
Move the constants to a class, and include the right class based on control flow.
Give different names to the constants, and keep the condition close to utilisation.
Move the constants to an external configuration file : it will be easier to identify that those constants may change.
1.2.278.2. Specs¶
Short name |
Constants/MultipleConstantDefinition |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.279. PHP Constant Usage¶
List of PHP constants being used.
<?php
const MY_CONST = 'Hello';
// PHP_EOL (native PHP Constant)
// MY_CONST (custom constant, not reported)
echo PHP_EOL . MY_CONST;
?>
See also Predefined Constants.
1.2.279.1. Specs¶
Short name |
Constants/PhpConstantUsage |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.280. Strange Name For Constants¶
Those constants looks like a typo from other names.
<?php
// This code looks OK : DIRECTORY_SEPARATOR is a native PHP constant
$path = $path . DIRECTORY_SEPARATOR . $file;
// Strange name DIRECOTRY_SEPARATOR
$path = $path . DIRECOTRY_SEPARATOR . $file;
?>
1.2.280.1. Suggestions¶
Fix any typo in the spelling of the constants
Tell us about common misspelling so we can upgrade this analysis
1.2.280.2. Specs¶
Short name |
Constants/StrangeName |
Rulesets |
|
Exakat since |
0.10.5 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.281. Undefined Constants¶
Constants definition can’t be located.
Those constants are not defined in the code, and will raise errors, or use the fallback mechanism of being treated like a string.
<?php
const A = 1;
define('B', 2);
// here, C is not defined in the code and is reported
echo A.B.C;
?>
It is recommended to define them all, or to avoid using them.
See also Constants.
1.2.281.1. Suggestions¶
Define the constant
Fix the name of the constant
Fix the namespace of the constant (FQN or use)
Remove the usage of the constant
1.2.281.2. Specs¶
Short name |
Constants/UndefinedConstants |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Available in |
1.2.282. Unused Constants¶
Those constants are defined in the code but never used. Defining unused constants slow down the application, as they are executed and stored in PHP hashtables.
<?php
// const-defined constant
const USED_CONSTANT = 0;
const UNUSED_CONSTANT = 1 + USED_CONSTANT;
// define-defined constant
define('ANOTHER_UNUSED_CONSTANT', 3);
?>
It is recommended to comment them out, and only define them when it is necessary.
1.2.282.1. Suggestions¶
Make use of the constant
Remove the constant
1.2.282.2. Specs¶
Short name |
Constants/UnusedConstants |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.283. Variable Constants¶
Variable constants are actually constants whose value is accessed via the function constant(). Otherwise, there is no way to dynamically access a constant (aka, when the developer has the name of the constant as a incoming parameter, and it requires the value of it).
<?php
const A = 'constant_value';
$constant_name = 'A';
$variableConstant = constant($constant_name);
?>
See also constant().
1.2.283.1. Specs¶
Short name |
Constants/VariableConstant |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.284. Call Order¶
This is a representation of the code. Each node is a function or method, and each link a is call from a method to another.
The only link is the possible call from a method to the other. All control flow is omitted, including conditional calls and loops.
<?php
function foo() {
bar();
foobar();
}
function bar() {
foobar();
}
function foobar() {
}
?>
From the above script, the resulting network will display ‘foo() -> bar(), foo() -> foobar(), bar() -> foobar()’ calls.
1.2.284.1. Specs¶
Short name |
Dump/CallOrder |
Rulesets |
|
Exakat since |
2.1.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.285. Collect Atom Counts¶
1.2.285.1. Specs¶
Short name |
Dump/CollectAtomCounts |
Rulesets |
|
Exakat since |
2.1.8 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.286. Collect Block Size¶
Collect block size for for, foreach, while, do…while, ifthen.
1.2.286.1. Specs¶
Short name |
Dump/CollectBlockSize |
Rulesets |
|
Exakat since |
2.2.0 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.287. Collect Static Class Changes¶
Collects changes to constants, methods and properties, within a class hierarchy.
<?php
class x {
protected $property = 1;
protected function method() {}
}
class y extends x {
// $property is changed
protected $property = 2;
// method is not changed
protected function method() {}
}
?>
1.2.287.1. Specs¶
Short name |
Dump/CollectClassChanges |
Rulesets |
|
Exakat since |
2.1.5 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.288. Collect Class Children Count¶
Count the number of class children for each class.
<?php
// 2 children
class a {}
// 1 children
class b extends a {}
// no children
class c extends b {}
// no children
class d extends a {}
?>
1.2.288.1. Specs¶
Short name |
Dump/CollectClassChildren |
Rulesets |
|
Exakat since |
2.0.3 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.289. Collect Class Constant Counts¶
This analysis collects the number of class constants per class or interface.
The count applies to classes, anonymous classes and interfaces. They are considered distinct one from another.
<?php
class foo {
// 3 constant
const A =1, B =2;
}
interface bar {
// 3 properties
const A=1, B=2, C=3;
}
?>
1.2.289.1. Specs¶
Short name |
Dump/CollectClassConstantCounts |
Rulesets |
|
Exakat since |
2.1.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.290. Collect Class Depth¶
Count the number of level of extends for classes.
<?php
class a {}
class b extends a {}
class c extends b {}
class d extends a {}
?>
1.2.290.1. Specs¶
Short name |
Dump/CollectClassDepth |
Rulesets |
|
Exakat since |
2.0.3 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.291. Collect Class Interface Counts¶
Collect the number of interfaces implemented per class.
<?php
// This class implements 3 interfaces
class x implements i, j, k {
// Some code
}
?>
1.2.291.1. Specs¶
Short name |
Dump/CollectClassInterfaceCounts |
Rulesets |
|
Exakat since |
2.0.3 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.292. Collect Class Traits Counts¶
Counts the number of trait used in a class.
<?php
// Use no traits
class x {}
// Use one trait
class y {
use TraitT;
}
?>
1.2.292.1. Specs¶
Short name |
Dump/CollectClassTraitsCounts |
Rulesets |
|
Exakat since |
2.1.7 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.293. Collect Classes Dependencies¶
Collect Classes Dependencies
1.2.293.1. Specs¶
Short name |
Dump/CollectClassesDependencies |
Rulesets |
|
Exakat since |
2.1.8 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.294. Collect Definitions Statistics¶
1.2.294.1. Specs¶
Short name |
Dump/CollectDefinitionsStats |
Rulesets |
|
Exakat since |
2.1.7 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.295. Collect Files Dependencies¶
Collect all dependencies between files, based on definitions and usage.
For example, file A.php, which defines de class A, is a dependence to a file B.php, which makes a call to a method from A, or use A as a typehint, etc..
1.2.295.1. Specs¶
Short name |
Dump/CollectFilesDependencies |
Rulesets |
|
Exakat since |
2.1.8 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.296. Foreach() Favorite¶
Collect the name used in foreach() loops. Then, sorts them in order of popularity.
1.2.296.1. Specs¶
Short name |
Dump/CollectForeachFavorite |
Rulesets |
|
Exakat since |
1.9.7 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.297. Collect Global Variables¶
Collect global variables names.
1.2.297.1. Specs¶
Short name |
Dump/CollectGlobalVariables |
Rulesets |
|
Exakat since |
2.1.7 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.298. Collect Literals¶
Collects all literals in the application, for inventory purposes.
1.2.298.1. Specs¶
Short name |
Dump/CollectLiterals |
Rulesets |
|
Exakat since |
1.9.5 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.299. Collect Local Variable Counts¶
This analysis collects the number of local variables used in a method or a function.
The count applies to functions, methods, closures and arrow functions.
Arguments and global variables are not counted. Static variables are.
<?php
function foo($arg) {
global $w;
// This is a local variable
$x = rand(1, 2);
return $x + $arg + $w;
}
?>
1.2.299.1. Specs¶
Short name |
Dump/CollectLocalVariableCounts |
Rulesets |
|
Exakat since |
2.1.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.300. Collect Mbstring Encodings¶
This analysis collects the encoding names, used by ext/mb functions.
<?php
mb_stotolower('PHP', 'iso-8859-1');
mb_stotolower('PHP', 'iso-8859-1');
?>
1.2.300.1. Specs¶
Short name |
Dump/CollectMbstringEncodings |
Rulesets |
|
Exakat since |
1.9.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.301. Collect Method Counts¶
This analysis collects the number of methods per class, trait or interface.
The count applies to classes, anonymous classes, traits and interfaces. They are considered distinct one from another.
<?php
class foo {
// 2 methods
function __construct() {}
function foo() {}
}
interface bar {
// 1 method
function a() ;
}
class barbar {
// 3 methods
function __construct() {}
function foo() {}
function a() {}
}
?>
1.2.301.1. Specs¶
Short name |
Dump/CollectMethodCounts |
Rulesets |
|
Exakat since |
2.1.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.302. Collect Native Calls Per Expressions¶
Computes the number of PHP native call per expression.
1.2.302.1. Specs¶
Short name |
Dump/CollectNativeCallsPerExpressions |
Rulesets |
|
Exakat since |
2.1.7 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.303. Collect Parameter Counts¶
This analysis collects the number of parameter per method.
The count applies to functions, methods, closures and arrow functions.
<?php
// parameter count on function : 1
function foo($a) { }
// parameter count on closure : 2
function ($b, $c = 2) {}
// parameter count on method : 0 (none)
class x {
function moo() { }
}
?>
1.2.303.1. Specs¶
Short name |
Dump/CollectParameterCounts |
Rulesets |
|
Exakat since |
1.9.6 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.304. Collect Parameter Names¶
This analysis collects the names of all parameters. It also counts the number of occurrences of each name.
The names are collected from functions, methods, closures and arrow functions. Compulsory and optional parameters are all processed.
<?php
// parameter $a
function foo($a) { }
// parameter $b, $c
function ($b, $c = 2) {}
// parameters in interfaces are counted too.
// Here, $a will be counted with the one above.
interfaces x {
function moo($a);
}
?>
1.2.304.1. Specs¶
Short name |
Dump/CollectParameterNames |
Rulesets |
|
Exakat since |
2.1.5 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.305. Collect Php Structures¶
Collect Php Structures
1.2.305.1. Specs¶
Short name |
Dump/CollectPhpStructures |
Rulesets |
|
Exakat since |
2.1.8 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.306. Collect Property Counts¶
This analysis collects the number of properties per class or trait.
The count applies to classes, anonymous classes and traits. They are considered distinct one from another.
Properties may be static or not. Visibility, default values and typehints are omitted.
<?php
class foo {
// 3 properties
private $p1, $p2, $p3;
}
trait foo {
// 3 properties
protected $p1;
public $p2 = 1, $p3;
}
?>
1.2.306.1. Specs¶
Short name |
Dump/CollectPropertyCounts |
Rulesets |
|
Exakat since |
2.1.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.307. Collect Readability¶
Measure readability for methods, functions and closures, then report them.
1.2.307.1. Specs¶
Short name |
Dump/CollectReadability |
Rulesets |
|
Exakat since |
2.1.7 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.308. Collect Use Counts¶
Count the number of use expression in a file. This count 4 uses.
<?php
use A as B;
use F\C, F\D, F\E;
?>
1.2.308.1. Specs¶
Short name |
Dump/CollectUseCounts |
Rulesets |
|
Exakat since |
2.1.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.309. Collect Variables¶
Collect all variables from the code. Their type is mentionned, as variable, object or array, depending on their usage.
1.2.309.1. Specs¶
Short name |
Dump/CollectVariables |
Rulesets |
|
Exakat since |
2.1.7 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.310. Constant Order¶
Order of dependency of constants.
Constants, either global or class, may be built using static expression. In turn, this means that constants have now a build order. For example :
<?php
// A is an independant global constant
const A = 1;
// B is an dependant global constant : it is built with A
const B = A + 1;
class x {
// x::C is an dependant class constant : it is built with A
const C = A + 3;
}
?>
The code above leads to the following order : A - B, C. A can be built without constraints, while B and C must be build when A is available. Note that B and C are both dependant on A, but are not dependant on each other.
The resulting tree displays the different relationship between the constants.
Note : define``constants are not considered here. Only ``const constants, global or class.
1.2.310.1. Specs¶
Short name |
Dump/ConstantOrder |
Rulesets |
|
Exakat since |
2.0.7 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.311. Cyclomatic Complexity¶
Calculate cyclomatic complexity for each methods, function, and closures.
1.2.311.1. Specs¶
Short name |
Dump/CyclomaticComplexity |
Rulesets |
|
Exakat since |
1.9.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.312. Dereferencing Levels¶
This is the counts of level of dereferencing.
Everytime a -> or ?-> operator are used, this count as one level of dereferencing.
Fluent interfaces tends to have very high levels of deferencing.
<?php
// one level of deferencing
$a->b;
$c->d();
// four levels of deferencing
$a->b->c()->d->e();
// also four levels of deferencing
$a->b?->c()->d->e();
?>
1.2.312.1. Specs¶
Short name |
Dump/DereferencingLevels |
Rulesets |
|
Exakat since |
1.9.6 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.313. Environment Variables¶
Collect all used Environment variables
1.2.313.1. Specs¶
Short name |
Dump/EnvironmentVariables |
Rulesets |
none |
Exakat since |
1.9.3 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.314. Environment Variable Usage¶
Collects all environment variables in the application, for inventory purposes.
<?php
$implicit_global = 1;
global $explicit_global;
function foo() {
$local_variable = 2;
}
?>
See also Variable scope.
1.2.314.1. Specs¶
Short name |
Dump/EnvironnementVariables |
Rulesets |
|
Exakat since |
1.9.5 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.315. Dump/FossilizedMethods¶
1.2.315.1. Specs¶
Short name |
Dump/FossilizedMethods |
Rulesets |
|
Exakat since |
2.1.5 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.316. Inclusions¶
Collect inclusions of files. This is based on include(), require(), include_once() and require_once() keywords.
<?php
// This is file 'A.php';
include 'B.php';
// Here, B.php includes A.php
?>
1.2.316.1. Specs¶
Short name |
Dump/Inclusions |
Rulesets |
|
Exakat since |
2.0.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.317. Indentation Levels¶
Collect all level of indentations for methods and functions.
<?php
function foo() {
$a = 1; // level 1
if ($b == 2) {
$c = 1; // level 2
}
$d = 4; // level 1
}
?>
1.2.317.1. Specs¶
Short name |
Dump/IndentationLevels |
Rulesets |
|
Exakat since |
1.9.3 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.318. New Order¶
Order in which new calls are done.
<?php
class x {}
// class Y has precedence over class X, as it needs to be called first to get to X
class y {
function foo() {
return new x();
}
}
?>
1.2.318.1. Specs¶
Short name |
Dump/NewOrder |
Rulesets |
|
Exakat since |
2.0.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.319. Links Between Parameter And Argument¶
Collect various stats about arguments and parameter usage.
A parameter is one slot in the method definition. An argument is a slot in the method call. Both are linked by the method and their respective position in the argument list.
Total number of argument usage, linked to a parameter : this excludes arguments from external libraries and native PHP functions. For reference.
Number of identical parameter : cases where argument and parameter have the same name.
Number of different parameter : cases where argument and parameter have the different name.
Number of expression argument : cases where argument is an expression
Number of constant argument : cases where the argument is a constant
<?php
function foo($a, $b) {
// some code
}
// $a is the same as the parameter
// $c is different from the paramter $b
foo($a, $c);
const C = 1;
// Foo is called with a constant (1rst argument)
// Foo is called with a expression (2nd argument)
foo(C, 1+3);
?>
1.2.319.1. Specs¶
Short name |
Dump/ParameterArgumentsLinks |
Rulesets |
|
Exakat since |
2.0.6 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.320. Typehinting Stats¶
This module collects statistics about typehinting usage.
1.2.320.1. Specs¶
Short name |
Dump/TypehintingStats |
Rulesets |
|
Exakat since |
1.9.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Available in |
1.2.321. Typehint Order¶
Topological order, based on typehints.
Each function, method that use typehint is a link between a type of data and another one. The argument typehint acts as a filter, and the returned type hint is the next step.
<?php
// This library imposes the following order : A -> B -> C
function foo(A $a) : B { }
function bar(B $b) : C { }
?>
1.2.321.1. Specs¶
Short name |
Dump/Typehintorder |
Rulesets |
|
Exakat since |
2.0.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.322. Exception Order¶
When catching exception, the most specialized exceptions must be in the early catch, and the most general exceptions must be in the later catch. Otherwise, the general catches intercept the exception, and the more specialized will not be read.
<?php
class A extends \Exception {}
class B extends A {}
try {
throw new A();
}
catch(A $a1) { }
catch(B $b2 ) {
// Never reached, as previous Catch is catching the early worm
}
?>
1.2.322.1. Suggestions¶
Remove one of the catch clause
1.2.322.2. Specs¶
Short name |
Exceptions/AlreadyCaught |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Examples |
|
Available in |
1.2.323. Can’t Throw Throwable¶
Classes extending
Throwablecan’t be thrown. The same applies to interfaces.
Although this code lints, PHP throws a Fatal error when executing or including it : Class fooThrowable cannot implement interface `Throwable <https://www.php.net/manual/en/class.throwable.php>`_, extend Exception or Error instead.
<?php
// This is the way to go
class fooException extends \Exception { }
// This is not possible and a lot of work
class fooThrowable implements \throwable { }
?>
See also Throwable, Exception and Error.
1.2.323.1. Suggestions¶
Extends the Exception class
Extends the Error class
1.2.323.2. Specs¶
Short name |
Exceptions/CantThrow |
Rulesets |
|
Exakat since |
1.3.3 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.324. Caught Variable¶
1.2.324.1. Suggestions¶
Make all caught constant consistent, and avoid using them for something else
1.2.324.2. Specs¶
Short name |
Exceptions/CatchE |
Rulesets |
|
Exakat since |
1.7.6 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.325. Catch Undefined Variable¶
Always initialize variable before the try block, when they are used in a catch block. If the exception is raised before the variable is defined, the catch block may have to handle an undefined variable, leading to more chaos.
<?php
$a = 1;
try {
mayThrowAnException();
$b = 2;
} catch (\Exception $e) {
// $a is already defined, as it was done before the try block
// $b may not be defined, as it was initialized after the exception-throwing expression
echo $a + $b;
}
?>
See also catch and Non-capturing exception catches in PHP 8.
1.2.325.1. Suggestions¶
Always define the variable used in the catch clause, before the try block.
1.2.325.2. Specs¶
Short name |
Exceptions/CatchUndefinedVariable |
Rulesets |
|
Exakat since |
2.1.5 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Available in |
1.2.326. Undefined Caught Exceptions¶
Those are exceptions that are caught in the code, but are not defined in the application.
They may be externally defined, such as in core PHP, extensions or libraries. Make sure those exceptions are useful to your application : otherwise, they are dead code.
<?php
try {
library_function($some, $args);
} catch (LibraryException $e) {
// This exception is not defined, and probably belongs to Library
print Library failed\n;
} catch (OtherLibraryException $e) {
// This exception is not defined, and probably do not belongs to this code
print Library failed\n;
} catch (\Exception $e) {
// This exception is a PHP standard exception
print Something went wrong, but not at Libary level\n;
}
?>
1.2.326.1. Suggestions¶
Remove the catch clause, as it is dead code
Make sure the exception is thrown by the underlying code
1.2.326.2. Specs¶
Short name |
Exceptions/CaughtButNotThrown |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.327. Caught Exceptions¶
Exceptions used in catch clause.
<?php
try {
foo();
} catch (MyException $e) {
fixException();
} finally {
clean();
}
?>
See also Exceptions.
1.2.327.1. Specs¶
Short name |
Exceptions/CaughtExceptions |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.328. Could Use Try¶
Some commands may raise exceptions. It is recommended to use the try/catch block to intercept those exceptions, and process them.
/ :
DivisionByZeroError% :
DivisionByZeroErrorintdiv() :
DivisionByZeroError<< :
ArithmeticError>> :
ArithmeticErrorPhar\:\:mungserver:PharExceptionPhar\:\:webphar:PharException
See also Predefined Exceptions, PharException.
1.2.328.1. Suggestions¶
Add a try/catch clause around those commands
Add a check on the values used with those operator : for example, check a dividend is not 0, or a bitshift is not negative
1.2.328.2. Specs¶
Short name |
Exceptions/CouldUseTry |
Rulesets |
|
Exakat since |
1.5.0 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.329. Defined Exceptions¶
This is the list of defined exceptions.
<?php
class myException extends \Exception {}
// A defined exception
throw new myException();
// not a defined exception : it is already defined.
throw new \RuntimeException();
?>
See also Exceptions.
1.2.329.1. Specs¶
Short name |
Exceptions/DefinedExceptions |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.330. Forgotten Thrown¶
An exception is instantiated, but not thrown.
<?php
class MyException extends \Exception { }
if ($error !== false) {
// This looks like 'throw' was omitted
new MyException();
}
?>
1.2.330.1. Suggestions¶
Remove the throw expression
Add the new to the throw expression
1.2.330.2. Specs¶
Short name |
Exceptions/ForgottenThrown |
Rulesets |
|
Exakat since |
0.10.2 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.331. PHP Exception¶
Mark an exception as a native exception. They may come from PHP standard distribution or an extension.
<?php
// From the native set
$a = new LogicException('Logic error');
throw $a;
// From an extension
throw new ZookeeperException('Zookeeper error');
?>
See also Exceptions.
1.2.331.1. Specs¶
Short name |
Exceptions/IsPhpException |
Rulesets |
|
Exakat since |
1.5.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.332. Large Try Block¶
Try block should enclosing only the expression that may emit an exception.
When writing large blocks of code in a try, it becomes difficult to understand where the expression is coming from. Large blocks may also lead to catch multiples exceptions, with a long list of catch clause.
In particular, the catch clause will resume the execution without knowing where the try was interrupted : there are no indication of achievement, even partial. In fact, catching an exception signals a very dirty situation.
<?php
// try is one expression only
try {
$database->query($query);
} catch (DatabaseException $e) {
// process exception
}
// Too many expressions around the one that may actually emit the exception
try {
$SQL = build_query($arguments);
$database = new Database($dsn);
$database->setOption($options);
$statement = $database->prepareQuery($SQL);
$result = $statement->query($query);
} catch (DatabaseException $e) {
// process exception
}
?>
This analysis reports try blocks that are 5 lines or more. This threshold may be configured with the directive tryBlockMaxSize. Catch clause, and finally are not considered here.
1.2.332.1. Suggestions¶
Reduce the amount of code in the block, by moving it before and after
Name |
Default |
Type |
Description |
tryBlockMaxSize |
5 |
integer |
Maximal number of expressions in the try block. |
See also and Exceptions.
1.2.332.2. Specs¶
Short name |
Exceptions/LargeTryBlock |
Rulesets |
|
Exakat since |
2.1.5 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Available in |
1.2.333. Long Preparation For Throw¶
When throwing an exception, move the preparing code in the exception. This will keep the
throwcall simple.
<?php
// Examples extracted from Alain Schlesser's blog
public function render( $view ): string {
if ( ! $this->views->has( $view ) ) {
switch ( gettype( $view ) ) {
case 'object':
$view = get_class( $view );
case 'string':
$message = sprintf(
'The requested View %s does not exist.',
$view
);
break;
default:
$message = sprintf(
'An unknown View type of %s was requested.',
$view
);
}
throw new ViewWasNotFound( $message );
}
echo $this->views->get( $view )
->render();
}
?>
1.2.333.1. Suggestions¶
Move the preparation into the Exception to keep the throw simple
Name |
Default |
Type |
Description |
preparationLineCount |
8 |
integer |
Minimal number of lines before the throw. |
See also and Structuring PHP Exceptions session.
1.2.333.2. Specs¶
Short name |
Exceptions/LongPreparation |
Rulesets |
|
Exakat since |
2.2.0 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.334. Multiple Exceptions Catch()¶
It is possible to have several distinct exceptions class caught by the same catch, preventing code repetition.
This is a new feature since PHP 7.1.
<?php
// PHP 7.1 and more recent
try {
throw new someException();
} catch (Single $s) {
doSomething();
} catch (oneType | anotherType $s) {
processIdentically();
} finally {
}
// PHP 7.0 and older
try {
throw new someException();
} catch (Single $s) {
doSomething();
} catch (oneType $s) {
processIdentically();
} catch (anotherType $s) {
processIdentically();
} finally {
}
?>
This is a backward incompatible feature of PHP 7.1.
1.2.334.1. Specs¶
Short name |
Exceptions/MultipleCatch |
Rulesets |
Appinfo, CE, CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, CompatibilityPHP70, All |
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.335. Overwritten Exceptions¶
In catch blocks, it is good practice to avoid overwriting the incoming exception, as information about the exception will be lost.
<?php
try {
doSomething();
} catch (SomeException $e) {
// $e is overwritten
$e = new anotherException($e->getMessage());
throw $e;
} catch (SomeOtherException $e) {
// $e is chained with the next exception
$e = new Exception($e->getMessage(), 0, $e);
throw $e;
}
?>
1.2.335.1. Suggestions¶
Use another variable name to create new values inside the catch
Use anonymous catch clause (no variable caught) in PHP 8.0, to make this explicit
1.2.336. Rethrown Exceptions¶
Throwing a caught exception is usually useless and dead code.
When exceptions are caught, they should be processed or transformed, but not rethrown as is.
Those issues often happen when a catch structure was positioned for debug purposes, but lost its usage later.
<?php
try {
doSomething();
} catch (Exception $e) {
throw $e;
}
?>
See also What are the best practices for catching and re-throwing exceptions? and Exception chaining.
1.2.336.1. Suggestions¶
Log the message of the exception for later usage.
Remove the try/catch and let the rest of the application handle this exception.
Chain the exception, by throwing a new exception, including the caught exception.
1.2.336.2. Specs¶
Short name |
Exceptions/Rethrown |
Rulesets |
|
Exakat since |
0.9.0 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.337. Throw Functioncall¶
The
throwkeyword expects to use an exception. Calling a function to prepare that exception before throwing it is possible, but forgetting the new keyword is also possible.
<?php
// Forgotten new
throw \RuntimeException('error!');
// Code is OK, function returns an exception
throw getException(ERROR_TYPE, 'error!');
function getException(ERROR_TYPE, $message) {
return new \RuntimeException($messsage);
}
?>
When the new keyword is forgotten, then the class constructor is used as a function name, and now exception is emitted, but an Undefined function fatal error is emitted.
See also Exceptions.
1.2.337.1. Suggestions¶
Add the new operator to the call
Make sure the function is really a functioncall, not a class name
Use return typehints for functions, so that Exception may be detected
1.2.337.2. Specs¶
Short name |
Exceptions/ThrowFunctioncall |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Instant (5 mins) |
Precision |
Medium |
Examples |
|
Available in |
1.2.338. Thrown Exceptions¶
Usage of throw keyword.
<?php
throw new MyException('Error happened');
?>
See also Exceptions.
1.2.338.1. Specs¶
Short name |
Exceptions/ThrownExceptions |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.339. Uncaught Exceptions¶
The following exceptions are thrown in the code, but are never caught.
<?php
// This exception is throw, but not caught. It will lead to a fatal error.
if ($message = check_for_error()) {
throw new My\Exception($message);
}
// This exception is throw, and caught.
try {
if ($message = check_for_error()) {
throw new My\Exception($message);
}
} catch (\Exception $e) {
doSomething();
}
?>
Either they will lead to a Fatal Error, or they have to be caught by an including application. This is a valid behavior for libraries, but is not for a final application.
See also Structuring PHP Exceptions.
1.2.339.1. Suggestions¶
Catch all the exceptions you throw
1.2.339.2. Specs¶
Short name |
Exceptions/UncaughtExceptions |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.340. Unthrown Exception¶
These are exceptions that are defined in the code but never thrown.
<?php
//This exception is defined but never used in the code.
class myUnusedException extends \Exception {}
//This exception is defined and used in the code.
class myUsedException extends \Exception {}
throw new myUsedException('I was called');
?>
See also Exceptions.
1.2.340.1. Specs¶
Short name |
Exceptions/Unthrown |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
ClearPHP |
|
Available in |
1.2.341. Unused Exception Variable¶
The variable from a catch clause is not used. It is expected to be used, either by chaining the exception, or logging the message.
In PHP 8.0, this variable may be omitted.
<?php
try{
doSomething();
} catch (A $a) {
// $a is caught, but not used here
} catch (B $b) {
// $b is caught, and used
log($b->getMessage());
} catch (C) {
// Caught and ignored (PHP 8.0 +)
}
?>
1.2.341.1. Suggestions¶
Drop the variable in the clause expression (PHP 8.0 and more recent)
Chain the exception
Log the exception message
1.2.341.2. Specs¶
Short name |
Exceptions/UnusedExceptionVariable |
Rulesets |
|
Exakat since |
2.2.0 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.342. Useless Catch¶
Catch clause should handle the exception with some work.
Among the task of a catch clause : log the exception, clean any mess that was introduced, fail graciously.
<?php
function foo($a) {
try {
$b = doSomething($a);
} catch (Throwable $e) {
// No log of the exception : no one knows it happened.
// return immediately ?
return false;
}
$b->complete();
return $b;
}
?>
See also Exceptions and Best practices for PHP exception handling.
1.2.342.1. Suggestions¶
Add a log call to the catch block
Handle correctly the exception
1.2.342.2. Specs¶
Short name |
Exceptions/UselessCatch |
Rulesets |
|
Exakat since |
1.1.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Examples |
|
Available in |
1.2.343. ext/amqp¶
Extension
amqp.
PHP AMQP Binding Library. This is an interface with the RabbitMQ AMQP client library. It is a C-language AMQP client library for use with v2.0+ of the RabbitMQ broker.
<?php
$cnn = new AMQPConnection();
$cnn->connect();
echo 'Used channels: ', $cnn->getUsedChannels(), PHP_EOL;
$ch = new AMQPChannel($cnn);
echo 'Used channels: ', $cnn->getUsedChannels(), PHP_EOL;
$ch = new AMQPChannel($cnn);
echo 'Used channels: ', $cnn->getUsedChannels(), PHP_EOL;
$ch = null;
echo 'Used channels: ', $cnn->getUsedChannels(), PHP_EOL;
?>
See also PHP AMQP Binding Library.
1.2.343.1. Specs¶
Short name |
Extensions/Extamqp |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.344. ext/apache¶
Extension Apache.
These functions are only available when running PHP as an Apache module.
<?php
$ret = apache_getenv(SERVER_ADDR);
echo $ret;
?>
See also Extension Apache and Apache server.
1.2.344.1. Specs¶
Short name |
Extensions/Extapache |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.345. ext/apc¶
Extension Alternative PHP Cache.
The Alternative PHP Cache (APC) is a free and open opcode cache for PHP. Its goal is to provide a free, open, and robust framework for caching and optimizing PHP intermediate code.
This extension is considered unmaintained and dead.
<?php
$bar = 'BAR';
apc_add('foo', $bar);
var_dump(apc_fetch('foo'));
echo PHP_EOL;
$bar = 'NEVER GETS SET';
apc_add('foo', $bar);
var_dump(apc_fetch('foo'));
echo PHP_EOL;
?>
See also Alternative PHP Cache.
1.2.345.1. Specs¶
Short name |
Extensions/Extapc |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
7.0- |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.346. ext/apcu¶
Extension
APCU.
APCu is APC stripped of opcode caching. The Alternative PHP Cache (APC) is a free and open opcode cache for PHP. Its goal is to provide a free, open, and robust framework for caching and optimizing PHP intermediate code.
<?php
$bar = 'BAR';
apcu_add('foo', $bar);
var_dump(apcu_fetch('foo'));
echo \n;
$bar = 'NEVER GETS SET';
apcu_add('foo', $bar);
var_dump(apcu_fetch('foo'));
echo \n;
?>
See also APCU, ext/apcu and krakjoe/apcu.
1.2.346.1. Specs¶
Short name |
Extensions/Extapcu |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.347. ext/array¶
Core functions processing arrays.
These functions manipulate arrays in various ways. Arrays are essential for storing, managing, and operating on sets of variables.
This is not a real extension : it is a documentation section, that helps classifying the functions.
<?php
function odd($var)
{
// returns whether the input integer is odd
return($var & 1);
}
function even($var)
{
// returns whether the input integer is even
return(!($var & 1));
}
$array1 = array('a'=>1, 'b'=>2, 'c'=>3, 'd'=>4, 'e'=>5);
$array2 = array(6, 7, 8, 9, 10, 11, 12);
echo 'Odd :'.PHP_EOL;
print_r(array_filter($array1, 'odd'));
echo 'Even:'.PHP_EOL;
print_r(array_filter($array2, 'even'));
?>
See also Arrays.
1.2.347.1. Specs¶
Short name |
Extensions/Extarray |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.348. ext/php-ast¶
PHP-AST extension (PHP 7.0 +).
<?php
$code = <<<'EOC'
<?php
$var = 42;
EOC;
var_dump(ast\parse_code($code, $version=50));
?>
See also ext/ast and Extension exposing PHP 7 abstract syntax tree.
1.2.348.1. Specs¶
Short name |
Extensions/Extast |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
7.0+ |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.349. ext/async¶
Concurrent Task Extension for PHP.
This extension provides concurrent Zend VM executions using native C fibers in PHP.
<?php
namespace Concurrent;
register_shutdown_function(function () {
echo "===> Shutdown function(s) execute here.\n";
});
$work = function (string $title): void {
var_dump($title);
};
Task::await(Task::async(function () use ($work) {
$defer = new Deferred();
Task::await(Task::async($work, 'A'));
Task::await(Task::async($work, 'B'));
Task::async(function () {
$defer = new Deferred();
Task::async(function () use ($defer) {
(new Timer(1000))->awaitTimeout();
$defer->resolve('H :)');
});
var_dump(Task::await($defer->awaitable()));
});
Task::async(function () use ($defer) {
var_dump(Task::await($defer->awaitable()));
});
$timer = new Timer(500);
Task::async(function () use ($timer, $defer, $work) {
$timer->awaitTimeout();
$defer->resolve('F');
Task::async($work, 'G');
});
var_dump('ROOT TASK DONE');
}));
Task::async($work, 'C');
Task::async(function () use ($work) {
(new Timer(0))->awaitTimeout();
Task::async($work, 'E');
});
Task::async(function ($v) {
var_dump(Task::await($v));
}, Deferred::value('D'));
var_dump('=> END OF MAIN SCRIPT');
?>
See also ext-async repository.
1.2.349.1. Specs¶
Short name |
Extensions/Extasync |
Rulesets |
|
Exakat since |
1.5.6 |
PHP Version |
7.3+ |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.350. ext/bcmath¶
Extension BC Math.
For arbitrary precision mathematics PHP offers the Binary Calculator which supports numbers of any size and precision up to 2147483647-1 (or 0x7FFFFFFF-1) decimals, represented as strings.
<?php
echo bcpow('2', '123');
//10633823966279326983230456482242756608
echo 2**123;
//1.0633823966279E+37
?>
See also BC Math Functions.
1.2.350.1. Specs¶
Short name |
Extensions/Extbcmath |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.351. ext/bzip2¶
Extension ext/bzip2.
Bzip2 Functions for PHP.
<?php
$file = '/tmp/foo.bz2';
$bz = bzopen($file, 'r') or die('Couldn\'t open $file for reading');
bzclose($bz);
?>
See also Bzip2 Functions.
1.2.351.1. Specs¶
Short name |
Extensions/Extbzip2 |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.352. ext/cairo¶
Extension ext/cairo.
Cairo is a native PHP extension to create and modify graphics using the Cairo Graphics Library.
<?php
// Example from https://github.com/gtkforphp/cairo/blob/master/examples/big-line.php
$width = 100;
$height = 100;
$sur = new CairoPSSurface(temp.ps, $width, $height);
$con = new CairoContext($sur);
$con->setSourceRgb(0,0,1);
$con->moveTo(50,50);
$con->lineTo(50000,50000);
$con->stroke();
$con->setSourceRgb(0,1,0);
$con->moveTo(50,50);
$con->lineTo(-50000,50000);
$con->stroke();
$con->setSourceRgb(1,0,0);
$con->moveTo(50,50);
$con->lineTo(50000,-50000);
$con->stroke();
$con->setSourceRgb(1,1,0);
$con->moveTo(50,50);
$con->lineTo(-50000,-50000);
$con->stroke();
$sur->writeToPng(dirname(__FILE__) . /big-line-php.png);
?>
See also cairo, gtkforphp/cairo.
1.2.352.1. Specs¶
Short name |
Extensions/Extcairo |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
Very high |
Available in |
1.2.353. ext/calendar¶
Extension ext/calendar.
The calendar extension presents a series of functions to simplify converting between different calendar formats.
<?php
$number = cal_days_in_month(CAL_GREGORIAN, 8, 2003); // 31
echo "There were {$number} days in August 2003";
?>
See also Calendar Functions.
1.2.353.1. Specs¶
Short name |
Extensions/Extcalendar |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.354. ext/cmark¶
Extension Cmark, for Common Mark.
cmark provides access to the reference implementation of CommonMark, a rationalized version of Markdown syntax with a specification.
<?php
$text = new CommonMark\Node\Text;
$text->literal = 'Hello World';
$document = new CommonMark\Node\Document;
$document->appendChild(
(new CommonMark\Node\Paragraph)
->appendChild($text));
echo CommonMark\Render\HTML($document);
?>
1.2.354.1. Specs¶
Short name |
Extensions/Extcmark |
Rulesets |
|
Exakat since |
1.2.7 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.355. ext/com¶
Extension COM and
.Net(Windows).
COM is an acronym for ‘Component Object Model’; it is an object orientated layer (and associated services) on top of DCE RPC (an open standard) and defines a common calling convention that enables code written in any language to call and interoperate with code written in any other language (provided those languages are COM aware).
<?php
$domainObject = new COM(WinNT://Domain);
foreach ($domainObject as $obj) {
echo $obj->Name . <br />;
}
?>
See also COM and .Net (Windows).
1.2.355.1. Specs¶
Short name |
Extensions/Extcom |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.356. ext/crypto¶
Extension ext/crypto (PECL).
Objective PHP binding of OpenSSL Crypto library.
<?php
use Crypto\Cipher;
use Crypto\AlgorihtmException;
$algorithm = 'aes-256-cbc';
if (!Cipher::hasAlgorithm($algorithm)) {
die('Algorithm $algorithm not found' . PHP_EOL);
}
try {
$cipher = new Cipher($algorithm);
// Algorithm method for retrieving algorithm
echo 'Algorithm: ' . $cipher->getAlgorithmName() . PHP_EOL;
// Params
$key_len = $cipher->getKeyLength();
$iv_len = $cipher->getIVLength();
echo 'Key length: ' . $key_len . PHP_EOL;
echo 'IV length: ' . $iv_len . PHP_EOL;
echo 'Block size: ' . $cipher->getBlockSize() . PHP_EOL;
// This is just for this example. You should never use such key and IV!
$key = str_repeat('x', $key_len);
$iv = str_repeat('i', $iv_len);
// Test data
$data1 = 'Test';
$data2 = 'Data';
$data = $data1 . $data2;
// Simple encryption
$sim_ct = $cipher->encrypt($data, $key, $iv);
// init/update/finish encryption
$cipher->encryptInit($key, $iv);
$iuf_ct = $cipher->encryptUpdate($data1);
$iuf_ct .= $cipher->encryptUpdate($data2);
$iuf_ct .= $cipher->encryptFinish();
// Raw data output (used base64 format for printing)
echo 'Ciphertext (sim): ' . base64_encode($sim_ct) . PHP_EOL;
echo 'Ciphertext (iuf): ' . base64_encode($iuf_ct) . PHP_EOL;
// $iuf_out == $sim_out
$ct = $sim_ct;
// Another way how to create a new cipher object (using the same algorithm and mode)
$cipher = Cipher::aes(Cipher::MODE_CBC, 256);
// Simple decryption
$sim_text = $cipher->decrypt($ct, $key, $iv);
// init/update/finish decryption
$cipher->decryptInit($key, $iv);
$iuf_text = $cipher->decryptUpdate($ct);
$iuf_text .= $cipher->decryptFinish();
// Raw data output ($iuf_out == $sim_out)
echo 'Text (sim): ' . $sim_text . PHP_EOL;
echo 'Text (iuf): ' . $iuf_text . PHP_EOL;
}
catch (AlgorithmException $e) {
echo $e->getMessage() . PHP_EOL;
}
?>
See also pecl crypto and php-crypto.
1.2.356.1. Specs¶
Short name |
Extensions/Extcrypto |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.357. ext/csprng¶
CSPRNG Functions : cryptographically secure pseudo-random number generator.
The CSPRNG API provides an easy and reliable way to generate crypto-strong random integers and bytes for use within cryptographic contexts.
<?php
$bytes = random_bytes(5);
var_dump(bin2hex($bytes));
//string(10) 385e33f741
?>
See also CSPRNG and Cryptographically secure pseudorandom number generator.
1.2.357.1. Specs¶
Short name |
Extensions/Extcsprng |
Rulesets |
|
Exakat since |
1.3.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.358. ext/ctype¶
Extension ext/ctype.
Ext/ctype checks whether a character or string falls into a certain character class according to the current locale.
<?php
$strings = array('AbCd1zyZ9', 'foo!#$bar');
foreach ($strings as $testcase) {
if (ctype_alnum($testcase)) {
echo "The string $testcase consists of all letters or digits.\n";
} else {
echo "The string $testcase does not consist of all letters or digits.\n";
}
}
?>
See also Ctype funtions.
1.2.358.1. Specs¶
Short name |
Extensions/Extctype |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.359. ext/curl¶
Extension curl.
PHP supports libcurl, a library created by Daniel Stenberg. It allows the connection and communication to many different types of servers with many different types of protocols.
<?php
$ch = curl_init("http://www.example.com/");
$fp = fopen("example_homepage.txt", "w");
curl_setopt($ch, CURLOPT_FILE, $fp);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_exec($ch);
curl_close($ch);
fclose($fp);
?>
See also Curl for PHP and curl.
1.2.359.1. Specs¶
Short name |
Extensions/Extcurl |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.360. ext/cyrus¶
Extension ext/cyrus.
The Cyrus IMAP server is electronic mail server software developed by Carnegie Mellon University.
<?php
$connexion = cyrus_connect ('localhost');
?>
See also Cyrus and Cyrus IMAP server.
1.2.360.1. Specs¶
Short name |
Extensions/Extcyrus |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.361. ext/date¶
Extension ext/date.
These functions allows the manipulation of date and time from the server where the PHP scripts are running.
<?php
$dt = new DateTime('2015-11-01 00:00:00', new DateTimeZone('America/New_York'));
echo 'Start: ', $dt->format('Y-m-d H:i:s P'), PHP_EOL;
$dt->add(new DateInterval('PT3H'));
echo 'End: ', $dt->format('Y-m-d H:i:s P'), PHP_EOL;
?>
See also Date and Time.
1.2.361.1. Specs¶
Short name |
Extensions/Extdate |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.362. ext/db2¶
Extension for IBM DB2, Cloudscape and Apache Derby.
This extension gives access to IBM DB2 Universal Database, IBM Cloudscape, and Apache Derby databases using the DB2 Call Level Interface (DB2 CLI).
<?php
$conn = db2_connect($database, $user, $password);
if ($conn) {
$stmt = db2_exec($conn, 'SELECT count(*) FROM animals');
$res = db2_fetch_array( $stmt );
echo $res[0] . PHP_EOL;
// Turn AUTOCOMMIT off
db2_autocommit($conn, DB2_AUTOCOMMIT_OFF);
// Delete all rows from ANIMALS
db2_exec($conn, 'DELETE FROM animals');
$stmt = db2_exec($conn, 'SELECT count(*) FROM animals');
$res = db2_fetch_array( $stmt );
echo $res[0] . PHP_EOL;
// Roll back the DELETE statement
db2_rollback( $conn );
$stmt = db2_exec( $conn, 'SELECT count(*) FROM animals' );
$res = db2_fetch_array( $stmt );
echo $res[0] . PHP_EOL;
db2_close($conn);
}
?>
See also IBM Db2.
1.2.362.1. Specs¶
Short name |
Extensions/Extdb2 |
Rulesets |
|
Exakat since |
1.1.8 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.363. ext/dba¶
Extension ext/dba.
These functions build the foundation for accessing Berkeley DB style databases.
<?php
$id = dba_open('/tmp/test.db', 'n', 'db2');
if (!$id) {
echo 'dba_open failed'.PHP_EOL;
exit;
}
dba_replace('key', 'This is an example!', $id);
if (dba_exists('key', $id)) {
echo dba_fetch('key', $id);
dba_delete('key', $id);
}
dba_close($id);
?>
See also Database (dbm-style) Abstraction Layer.
1.2.363.1. Specs¶
Short name |
Extensions/Extdba |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.364. ext/decimal¶
Extension php-decimal, by
Rudi Theunissen.
This library provides a PHP extension that adds support for correctly-rounded, arbitrary-precision decimal floating point arithmetic. Applications that rely on accurate numbers (ie. money, measurements, or mathematics) can use Decimal instead of float or string to represent numerical values.
<?php
use Decimal\Decimal;
$op1 = new Decimal(0.1, 4);
$op2 = 0.123456789;
print_r($op1 + $op2);
use Decimal\Decimal;
/**
* @param int $n The factorial to calculate, ie. $n!
* @param int $p The precision to calculate the factorial to.
*
* @return Decimal
*/
function factorial(int $n, int $p = Decimal::DEFAULT_PRECISION): Decimal
{
return $n < 2 ? new Decimal($n, $p) : $n * factorial($n - 1, $p);
}
echo factorial(10000, 32);
?>
See also PHP Decimal and libmpdec.
1.2.364.1. Specs¶
Short name |
Extensions/Extdecimal |
Rulesets |
|
Exakat since |
1.5.2 |
PHP Version |
7.0+ |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
Very high |
Available in |
1.2.365. ext/dio¶
Extension DIO : Direct Input Output.
PHP supports the direct io functions as described in the Posix Standard (Section 6) for performing I/O functions at a lower level than the C-Language stream I/O functions
<?php
$fd = dio_open('/dev/ttyS0', O_RDWR | O_NOCTTY | O_NONBLOCK);
dio_close($fd);
?>
See also DIO.
1.2.365.1. Specs¶
Short name |
Extensions/Extdio |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.366. ext/dom¶
Extension Document Object Model.
The DOM extension allows the manipulation of XML documents through the DOM API with PHP.
<?php
$dom = new DOMDocument('1.0', 'utf-8');
$element = $dom->createElement('test', 'This is the root element!');
// We insert the new element as root (child of the document)
$dom->appendChild($element);
echo $dom->saveXML();
?>
See also Document Object Model.
1.2.366.1. Specs¶
Short name |
Extensions/Extdom |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.367. ext/ds¶
Extension Data Structures : Data structures.
See also : Efficient data structures for PHP 7.
<?php
$vector = new \Ds\Vector();
$vector->push('a');
$vector->push('b', 'c');
$vector[] = 'd';
print_r($vector);
?>
1.2.367.1. Specs¶
Short name |
Extensions/Extds |
Rulesets |
|
Exakat since |
0.10.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.368. ext/eaccelerator¶
Extension Eaccelerator.
eAccelerator is a free open-source PHP accelerator & optimizer.
See also Eaccelerator and eaccelerator/eaccelerato.
1.2.368.1. Specs¶
Short name |
Extensions/Exteaccelerator |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.369. ext/eio¶
Extension EIO.
This is a PHP extension wrapping functions of the libeio library written by Marc Lehmann.
Libeio is a an asynchronous I/O library. Features basically include asynchronous versions of POSIX API(read, write, open, close, stat, unlink, fdatasync, mknod, readdir etc.); sendfile (native on Solaris, Linux, HP-UX, FreeBSD); readahead. libeio itself emulates the system calls, if they are not available on specific(UNIX-like) platform.
<?php
$str = str_repeat('1', 20);
$filename = '/tmp/tmp_file' .uniqid();
@unlink($filename);
touch($filename);
eio_open($filename, EIO_O_RDWR, NULL, EIO_PRI_DEFAULT, function($filename, $fd) use ($str) {
eio_write($fd, $str, strlen($str), 0, null, function($fd, $written) use ($str, $filename) {
var_dump([
'written' => $written,
'strlen' => strlen($str),
'filesize' => filesize($filename),
'count' => substr_count(file_get_contents($filename), '1')
]);
}, $fd);
}, $filename);
eio_event_loop();
?>
See also libeio, PHP extension for libeio.
1.2.369.1. Specs¶
Short name |
Extensions/Exteio |
Rulesets |
|
Exakat since |
1.3.3 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.370. ext/enchant¶
Extension Enchant.
Enchant is the PHP binding for the Enchant spelling library. Enchant steps in to provide uniformity and conformity on top of all spelling libraries, and implement certain features that may be lacking in any individual provider library.
<?php
$tag = 'en_US';
$r = enchant_broker_init();
$bprovides = enchant_broker_describe($r);
echo 'Current broker provides the following backend(s):'.PHP_EOL;
print_r($bprovides);
$dicts = enchant_broker_list_dicts($r);
print_r($dicts);
if (enchant_broker_dict_exists($r,$tag)) {
$d = enchant_broker_request_dict($r, $tag);
$dprovides = enchant_dict_describe($d);
echo 'dictionary $tag provides:'.PHP_EOL;
$wordcorrect = enchant_dict_check($d, 'soong');
print_r($dprovides);
if (!$wordcorrect) {
$suggs = enchant_dict_suggest($d, 'soong');
echo 'Suggestions for "soong":';
print_r($suggs);
}
enchant_broker_free_dict($d);
} else {
}
enchant_broker_free($r);
?>
See also Enchant spelling library and Enchant.
1.2.370.1. Specs¶
Short name |
Extensions/Extenchant |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.371. ext/ereg¶
Extension ext/ereg.
<?php
if (ereg ('([0-9]{4})-([0-9]{1,2})-([0-9]{1,2})', $date, $regs)) {
echo $regs[3].'.'.$regs[2].'.'.$regs[1];
} else {
echo 'Invalid date format: '.$date;
}
?>
See also Ereg.
1.2.371.1. Specs¶
Short name |
Extensions/Extereg |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.372. ext/ev¶
Extension ev.
ext/ev is a high performance full-featured event loop written in C.
<?php
// Create and start timer firing after 2 seconds
$w1 = new EvTimer(2, 0, function () {
echo '2 seconds elapsed'.PHP_EOL;
});
// Create and launch timer firing after 2 seconds repeating each second
// until we manually stop it
$w2 = new EvTimer(2, 1, function ($w) {
echo 'is called every second, is launched after 2 seconds'.PHP_EOL;
echo 'iteration = ', Ev::iteration(), PHP_EOL;
// Stop the watcher after 5 iterations
Ev::iteration() == 5 and $w->stop();
// Stop the watcher if further calls cause more than 10 iterations
Ev::iteration() >= 10 and $w->stop();
});
// Create stopped timer. It will be inactive until we start it ourselves
$w_stopped = EvTimer::createStopped(10, 5, function($w) {
echo 'Callback of a timer created as stopped'.PHP_EOL;
// Stop the watcher after 2 iterations
Ev::iteration() >= 2 and $w->stop();
});
// Loop until Ev::stop() is called or all of watchers stop
Ev::run();
// Start and look if it works
$w_stopped->start();
echo 'Run single iteration'.PHP_EOL;
Ev::run(Ev::RUN_ONCE);
echo 'Restart the second watcher and try to handle the same events, but don\'t block'.PHP_EOL;
$w2->again();
Ev::run(Ev::RUN_NOWAIT);
$w = new EvTimer(10, 0, function() {});
echo 'Running a blocking loop'.PHP_EOL;
Ev::run();
echo 'END'.PHP_EOL;
?>
1.2.372.1. Specs¶
Short name |
Extensions/Extev |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.373. ext/event¶
Extension event.
This is an extension to efficiently schedule I/O, time and signal based events using the best I/O notification mechanism available for specific platform. This is a port of libevent to the PHP infrastructure.
<?php
// Read callback
function readcb($bev, $base) {
//$input = $bev->input; //$bev->getInput();
//$pos = $input->search('TTP');
$pos = $bev->input->search('TTP');
while (($n = $bev->input->remove($buf, 1024)) > 0) {
echo $buf;
}
}
// Event callback
function eventcb($bev, $events, $base) {
if ($events & EventBufferEvent::CONNECTED) {
echo 'Connected.';
} elseif ($events & (EventBufferEvent::ERROR | EventBufferEvent::EOF)) {
if ($events & EventBufferEvent::ERROR) {
echo 'DNS error: ', $bev->getDnsErrorString(), PHP_EOL;
}
echo 'Closing'.PHP_EOL;
$base->exit();
exit('Done'.PHP_EOL);
}
}
if ($argc != 3) {
echo <<<EOS
Trivial HTTP 0.x client
Syntax: php {$argv[0]} [hostname] [resource]
Example: php {$argv[0]} www.google.com /
EOS;
exit();
}
$base = new EventBase();
$dns_base = new EventDnsBase($base, TRUE); // We'll use async DNS resolving
if (!$dns_base) {
exit('Failed to init DNS Base'.PHP_EOL);
}
$bev = new EventBufferEvent($base, /* use internal socket */ NULL,
EventBufferEvent::OPT_CLOSE_ON_FREE | EventBufferEvent::OPT_DEFER_CALLBACKS,
'readcb', /* writecb */ NULL, 'eventcb'
);
if (!$bev) {
exit('Failed creating bufferevent socket'.PHP_EOL);
}
//$bev->setCallbacks('readcb', /* writecb */ NULL, 'eventcb', $base);
$bev->enable(Event::READ | Event::WRITE);
$output = $bev->output; //$bev->getOutput();
if (!$output->add(
'GET '.$argv[2].' HTTP/1.0'."\r\n".
'Host: '.$argv[1]."\r\n".
'Connection: Close'.\r\n\r\n
)) {
exit('Failed adding request to output buffer\n');
}
if (!$bev->connectHost($dns_base, $argv[1], 80, EventUtil::AF_UNSPEC)) {
exit('Can\'t connect to host '.$argv[1].PHP_EOL);
}
$base->dispatch();
?>
1.2.373.1. Specs¶
Short name |
Extensions/Extevent |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.374. ext/exif¶
Extension EXIF : Exchangeable image file format.
The EXIF extension manipulates image meta data.
<?php
echo 'test1.jpg:<br />';
$exif = exif_read_data('tests/test1.jpg', 'IFD0');
echo $exif===false ? 'No header data found.<br />' : 'Image contains headers<br />';
$exif = exif_read_data('tests/test2.jpg', 0, true);
echo 'test2.jpg:<br />';
foreach ($exif as $key => $section) {
foreach ($section as $name => $val) {
echo $key.$name.': '.$val.'<br />';
}
}
?>
See also Exchangeable image information.
1.2.374.1. Specs¶
Short name |
Extensions/Extexif |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.375. ext/expect¶
Extension Expect.
This extension allows to interact with processes through PTY. You may consider using the expect:// wrapper with the filesystem functions which provide a simpler and more intuitive interface.
<?php
ini_set('expect.loguser', 'Off');
$stream = fopen('expect://ssh root@remotehost uptime', 'r');
$cases = array (
array (0 => 'password:', 1 => PASSWORD)
);
switch (expect_expectl ($stream, $cases)) {
case PASSWORD:
fwrite ($stream, 'password'.PHP_EOL);
break;
default:
die ('Error was occurred while connecting to the remote host!'.PHP_EOL);
}
while ($line = fgets($stream)) {
print $line;
}
fclose ($stream);
?>
See also expect.
1.2.375.1. Specs¶
Short name |
Extensions/Extexpect |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.376. ext/fam¶
File Alteration Monitor extension.
FAM monitors files and directories, notifying interested applications of changes.
ext/FAM is not available for Windows
<?php
$fam = fam_open('myApplication');
fam_monitor_directory($fam, '/tmp');
fam_close($fam);
?>
See also File Alteration Monitor.
1.2.376.1. Specs¶
Short name |
Extensions/Extfam |
Rulesets |
|
Exakat since |
0.12.8 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.377. ext/fann¶
Extension
FANN: Fast Artificial Neural Network.
PHP binding for FANN library which implements multi-layer artificial neural networks with support for both fully connected and sparsely connected networks.
<?php
$num_input = 2;
$num_output = 1;
$num_layers = 3;
$num_neurons_hidden = 3;
$desired_error = 0.001;
$max_epochs = 500000;
$epochs_between_reports = 1000;
$ann = fann_create_standard($num_layers, $num_input, $num_neurons_hidden, $num_output);
if ($ann) {
fann_set_activation_function_hidden($ann, FANN_SIGMOID_SYMMETRIC);
fann_set_activation_function_output($ann, FANN_SIGMOID_SYMMETRIC);
$filename = dirname(__FILE__) . '/xor.data';
if (fann_train_on_file($ann, $filename, $max_epochs, $epochs_between_reports, $desired_error))
fann_save($ann, dirname(__FILE__) . '/xor_float.net');
fann_destroy($ann);
}
?>
See also extension FANN, PHP-ML, Rubix ML and lib FANN.
1.2.377.1. Specs¶
Short name |
Extensions/Extfann |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.378. ext/fdf¶
Extension ext/fdf.
Forms Data Format (FDF) is a format for handling forms within PDF documents.
<?php
$outfdf = fdf_create();
fdf_set_value($outfdf, 'volume', $volume, 0);
fdf_set_file($outfdf, 'http:/testfdf/resultlabel.pdf');
fdf_save($outfdf, 'outtest.fdf');
fdf_close($outfdf);
Header('Content-type: application/vnd.fdf');
$fp = fopen('outtest.fdf', 'r');
fpassthru($fp);
unlink('outtest.fdf');
?>
See also Form Data Format.
1.2.378.1. Specs¶
Short name |
Extensions/Extfdf |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.379. ext/ffi¶
Extension
FFI: Foreign Function Interface .
This extension allows the loading of shared libraries (.DLL or .so), calling of C functions and accessing of C data structures in pure PHP, without having to have deep knowledge of the Zend extension API, and without having to learn a third “intermediate” language. The public API is implemented as a single class FFI with several static methods (some of them may be called dynamically), and overloaded object methods, which perform the actual interaction with C data.
<?php
//Example : Calling a function from shared library
// create FFI object, loading libc and exporting function printf()
$ffi = FFI::cdef(
"int printf(const char *format, ...);", // this is a regular C declaration
"libc.so.6");
// call C's printf()
$ffi->printf("Hello %s!\n", "world");
?>
See also Foreign Function Interface, and ext/ffi and A PHP Compiler, aka The FFI Rabbit Hole.
1.2.379.1. Specs¶
Short name |
Extensions/Extffi |
Rulesets |
|
Exakat since |
1.7.9 |
PHP Version |
7.4+ |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.380. ext/ffmpeg¶
Extension
ffmpegfor PHP.
ffmpeg-php is an extension for PHP that adds an easy to use, object-oriented API for accessing and retrieving information from video and audio files.
<?php
$movie = new ffmpeg_movie($path_to_media, $persistent);
echo 'The movie lasts '.$movie->getDuration().' seconds';
?>
See also ffmpeg-php and FFMPEG.
1.2.380.1. Specs¶
Short name |
Extensions/Extffmpeg |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.381. ext/file¶
Filesystem functions from standard.
Extension that handle access to file on the file system.
<?php
$row = 1;
if (($handle = fopen('test.csv', 'r')) !== FALSE) {
while (($data = fgetcsv($handle, 1000, ',')) !== FALSE) {
$num = count($data);
echo '<p> $num fields in line $row: <br /></p>'.PHP_EOL;
$row++;
for ($c=0; $c < $num; $c++) {
echo $data[$c] . '<br />'.PHP_EOL;
}
}
fclose($handle);
}
?>
See also filesystem.
1.2.381.1. Specs¶
Short name |
Extensions/Extfile |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.382. ext/fileinfo¶
Extension ext/fileinfo.
This module guesses the content type and encoding of a file by looking for certain magic byte sequences at specific positions within the file.
<?php
$finfo = finfo_open(FILEINFO_MIME_TYPE); // return mime type ala mimetype extension
foreach (glob('*') as $filename) {
echo finfo_file($finfo, $filename) . PHP_EOL;
}
finfo_close($finfo);
?>
See also Filinfo.
1.2.382.1. Specs¶
Short name |
Extensions/Extfileinfo |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.383. ext/filter¶
Extension filter.
This extension filters data by either validating or sanitizing it.
<?php
$email_a = 'joe@example.com';
$email_b = 'bogus';
if (filter_var($email_a, FILTER_VALIDATE_EMAIL)) {
echo 'This ($email_a) email address is considered valid.'.PHP_EOL;
}
if (filter_var($email_b, FILTER_VALIDATE_EMAIL)) {
echo 'This ($email_b) email address is considered valid.'.PHP_EOL;
} else {
echo 'This ($email_b) email address is considered invalid.'.PHP_EOL;
}
?>
See also Data filtering.
1.2.383.1. Specs¶
Short name |
Extensions/Extfilter |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.384. ext/fpm¶
Extension FPM, FastCGI Process Manager.
FPM (FastCGI Process Manager) is an alternative PHP FastCGI implementation with some additional features (mostly) useful for heavy-loaded sites. .. code-block:: php
- <?php
echo $text; fastcgi_finish_request( );
?>
See also FastCGI Process Manager.
1.2.384.1. Specs¶
Short name |
Extensions/Extfpm |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.385. ext/ftp¶
Extension FTP.
The functions in this extension implement client access to files servers speaking the File Transfer Protocol (FTP) as defined in RFC 959.
<?php
// set up basic connection
$conn_id = ftp_connect($ftp_server);
// login with username and password
$login_result = ftp_login($conn_id, $ftp_user_name, $ftp_user_pass);
// check connection
if ((!$conn_id) || (!$login_result)) {
echo 'FTP connection has failed!';
echo 'Attempted to connect to $ftp_server for user $ftp_user_name';
exit;
} else {
echo 'Connected to $ftp_server, for user $ftp_user_name';
}
// upload the file
$upload = ftp_put($conn_id, $destination_file, $source_file, FTP_BINARY);
// check upload status
if (!$upload) {
echo 'FTP upload has failed!';
} else {
echo 'Uploaded $source_file to $ftp_server as $destination_file';
}
// close the FTP stream
ftp_close($conn_id);
?>
See also FTP.
1.2.385.1. Specs¶
Short name |
Extensions/Extftp |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.386. ext/gd¶
Extension GD for PHP.
This extension allows PHP to create and manipulate image files in a variety of different image formats, including GIF, PNG, JPEG, WBMP, and XPM.
<?php
header("Content-type: image/png");
$string = $_GET['text'];
$im = imagecreatefrompng("images/button1.png");
$orange = imagecolorallocate($im, 220, 210, 60);
$px = (imagesx($im) - 7.5 * strlen($string)) / 2;
imagestring($im, 3, $px, 9, $string, $orange);
imagepng($im);
imagedestroy($im);
?>
See also Image Processing and GD.
1.2.386.1. Specs¶
Short name |
Extensions/Extgd |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.387. ext/gearman¶
Extension Gearman.
Gearman is a generic application framework for farming out work to multiple machines or processes.
<?php
# Create our client object.
$gmclient= new GearmanClient();
# Add default server (localhost).
$gmclient->addServer();
echo 'Sending job'.PHP_EOL;
# Send reverse job
do
{
$result = $gmclient->doNormal('reverse', 'Hello!');
# Check for various return packets and errors.
switch($gmclient->returnCode())
{
case GEARMAN_WORK_DATA:
echo 'Data: '.$result . PHP_EOL;;
break;
case GEARMAN_WORK_STATUS:
list($numerator, $denominator)= $gmclient->doStatus();
echo 'Status: '.$numerator.'/'.$denominator.' complete'. PHP_EOL;
break;
case GEARMAN_WORK_FAIL:
echo 'Failed\n';
exit;
case GEARMAN_SUCCESS:
echo 'Success: $result\n';
break;
default:
echo 'RET: ' . $gmclient->returnCode() . PHP_EOL;
exit;
}
}
while($gmclient->returnCode() != GEARMAN_SUCCESS);
?>
See also Gearman on PHP and Gearman.
1.2.387.1. Specs¶
Short name |
Extensions/Extgearman |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.388. ext/gender¶
Gender extension.
The Gender PHP extension is a port of the gender.c program originally written by Joerg Michael. Its main purpose is to find out the gender of firstnames, based on a database of over 40000 firstnames from 54 countries.
<?php
namespace Gender;
$gender = new Gender;
$name = 'Milene';
$country = Gender::FRANCE;
$result = $gender->get($name, $country);
$data = $gender->country($country);
switch($result) {
case Gender::IS_FEMALE:
printf('The name %s is female in %s\n', $name, $data['country']);
break;
case Gender::IS_MOSTLY_FEMALE:
printf('The name %s is mostly female in %s\n', $name, $data['country']);
break;
case Gender::IS_MALE:
printf('The name %s is male in %s\n', $name, $data['country']);
break;
case Gender::IS_MOSTLY_MALE:
printf('The name %s is mostly male in %s\n', $name, $data['country']);
break;
case Gender::IS_UNISEX_NAME:
printf('The name %s is unisex in %s\n', $name, $data['country']);
break;
case Gender::IS_A_COUPLE:
printf('The name %s is both male and female in %s\n', $name, $data['country']);
break;
case Gender::NAME_NOT_FOUND:
printf('The name %s was not found for %s\n', $name, $data['country']);
break;
case Gender::ERROR_IN_NAME:
echo 'There is an error in the given name!'.PHP_EOL;
break;
default:
echo 'An error occurred!'.PHP_EOL;
break;
}
?>
See also ext/gender manual and genderReader.
1.2.388.1. Specs¶
Short name |
Extensions/Extgender |
Rulesets |
|
Exakat since |
0.11.6 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.389. ext/geoip¶
Extension geoip for PHP.
The GeoIP extension allows the localisation of an IP address.
<?php
$org = geoip_org_by_name('www.example.com');
if ($org) {
echo 'This host IP is allocated to: ' . $org;
}
?>
See also GeoIP.
1.2.389.1. Specs¶
Short name |
Extensions/Extgeoip |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.390. ext/gettext¶
Extension Gettext.
The gettext functions implement an NLS (Native Language Support) API which can be used to internationalize your PHP applications.
<?php
// Set language to German
putenv('LC_ALL=de_DE');
setlocale(LC_ALL, 'de_DE');
// Specify location of translation tables
bindtextdomain('myPHPApp', './locale');
// Choose domain
textdomain('myPHPApp');
// Translation is looking for in ./locale/de_DE/LC_MESSAGES/myPHPApp.mo now
// Print a test message
echo gettext('Welcome to My PHP Application');
// Or use the alias _() for gettext()
echo _('Have a nice day');
?>
See also Gettext and ext/gettext
1.2.390.1. Specs¶
Short name |
Extensions/Extgettext |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.391. ext/gmagick¶
Extension gmagick.
Gmagick is a php extension to create, modify and obtain meta information of images using the GraphicsMagick API.
<?php
//Instantiate a new Gmagick object
$image = new Gmagick('example.jpg');
//Make thumbnail from image loaded. 0 for either axes preserves aspect ratio
$image->thumbnailImage(100, 0);
//Create a border around the image, then simulate how the image will look like as an oil painting
//Note the chaining of mutator methods which is supported in gmagick
$image->borderImage(yellow, 8, 8)->oilPaintImage(0.3);
//Write the current image at the current state to a file
$image->write('example_thumbnail.jpg');
?>
See also PHP gmagick and gmagick.
1.2.391.1. Specs¶
Short name |
Extensions/Extgmagick |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.392. ext/gmp¶
Extension ext/gmp.
These functions allow for arbitrary-length integers to be worked with using the GNU MP library.
<?php
$pow1 = gmp_pow('2', 131);
echo gmp_strval($pow1) . PHP_EOL;
$pow2 = gmp_pow('0', 0);
echo gmp_strval($pow2) . PHP_EOL;
$pow3 = gmp_pow('2', -1); // Negative exp, generates warning
echo gmp_strval($pow3) . PHP_EOL;
?>
See also GMP and GNU MP library.
1.2.392.1. Specs¶
Short name |
Extensions/Extgmp |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.393. ext/gnupgp¶
Extension GnuPG.
This module allows you to interact with gnupg.
<?php
// init gnupg
$res = gnupg_init();
// not really needed. Clearsign is default
gnupg_setsignmode($res,GNUPG_SIG_MODE_CLEAR);
// add key with passphrase 'test' for signing
gnupg_addsignkey($res,"8660281B6051D071D94B5B230549F9DC851566DC","test");
// sign
$signed = gnupg_sign($res,"just a test");
echo $signed;
?>
- See also Gnupg Function for PHP <http://www.php.net/manual/en/book.`gnupg.php>`_ and
GnuPG <https://www.`gnupg.org/>`_.
1.2.393.1. Specs¶
Short name |
Extensions/Extgnupg |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.394. ext/grpc¶
Extension for GRPC : A high performance, open-source universal RPC framework.
<?php
//https://github.com/grpc/grpc/blob/master/examples/php/greeter_client.php
require dirname(__FILE__).'/vendor/autoload.php';
// The following includes are needed when using protobuf 3.1.0
// and will suppress warnings when using protobuf 3.2.0+
@include_once dirname(__FILE__).'/helloworld.pb.php';
@include_once dirname(__FILE__).'/helloworld_grpc_pb.php';
function greet($name)
{
$client = new Helloworld\GreeterClient('localhost:50051', [
'credentials' => Grpc\ChannelCredentials::createInsecure(),
]);
$request = new Helloworld\HelloRequest();
$request->setName($name);
list($reply, $status) = $client->SayHello($request)->wait();
$message = $reply->getMessage();
return $message;
}
$name = !empty($argv[1]) ? $argv[1] : 'world';
echo greet($name).\n;
?>
See also GRPC and GRPC on PECL.
1.2.394.1. Specs¶
Short name |
Extensions/Extgrpc |
Rulesets |
|
Exakat since |
0.11.3 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.395. ext/hash¶
Extension for HASH Message Digest Framework.
Message Digest (hash) engine. Allows direct or incremental processing of arbitrary length messages using a variety of hashing algorithms.
<?php
/* Create a file to calculate hash of */
file_put_contents('example.txt', 'The quick brown fox jumped over the lazy dog.');
echo hash_file('md5', 'example.txt');
?>
See also HASH Message Digest Framework.
1.2.395.1. Specs¶
Short name |
Extensions/Exthash |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.396. ext/hrtime¶
High resolution timing Extension.
The HRTime extension implements a high resolution StopWatch class. It uses the best possible API on different platforms which brings resolution up to nanoseconds. It also makes possible to implement a custom stopwatch using low level ticks delivered by the underlaying system.
<?php
$c = new HRTime\StopWatch;
$c->start();
/* measure this code block execution */
for ($i = 0; $i < 1024*1024; $i++);
$c->stop();
$elapsed0 = $c->getLastElapsedTime(HRTime\Unit::NANOSECOND);
/* measurement is not running here*/
for ($i = 0; $i < 1024*1024; $i++);
$c->start();
/* measure this code block execution */
for ($i = 0; $i < 1024*1024; $i++);
$c->stop();
$elapsed1 = $c->getLastElapsedTime(HRTime\Unit::NANOSECOND);
$elapsed_total = $c->getElapsedTime(HRTime\Unit::NANOSECOND);
?>
See also ext/hrtime manual.
1.2.396.1. Specs¶
Short name |
Extensions/Exthrtime |
Rulesets |
|
Exakat since |
1.1.5 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.397. ext/pecl_http¶
Extension HTTP.
This HTTP extension aims to provide a convenient and powerful set of functionalities for one of PHP major applications.
It eases handling of HTTP URL, headers and messages, provides means for negotiation of a client’s preferred content type, language and charset, as well as a convenient way to send any arbitrary data with caching and resuming capabilities.
It provides powerful request functionality with support for parallel requests.
<?php
$client = new http\Client;
$client->setSslOptions(array("verifypeer" => true));
$client->addSslOptions(array("verifyhost" => 2));
$client->enqueue($req = new http\Client\Request("GET", "https://twitter.com/"));
$client->send();
$ti = (array) $client->getTransferInfo($req);
var_dump($ti);
?>
See also ext-http and pecl_http.
1.2.397.1. Specs¶
Short name |
Extensions/Exthttp |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.398. ext/ibase¶
Extensions
InterbaseandFirebird.
Firebird is a relational database offering many ISO SQL-2003 features that runs on Linux, Windows, and a variety of Unix platforms.
<?php
$host = 'localhost:/path/to/your.gdb';
$dbh = ibase_connect($host, $username, $password);
$stmt = 'SELECT * FROM tblname';
$sth = ibase_query($dbh, $stmt) or die(ibase_errmsg());
?>
See also Firebase / Interbase and Firebird.
1.2.398.1. Specs¶
Short name |
Extensions/Extibase |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.399. ext/iconv¶
Extension ext/iconv.
With this module, you can turn a string represented by a local character set into the one represented by another character set, which may be the Unicode character set.
<?php
$text = "This is the Euro symbol '€'.";
echo 'Original : ', $text, PHP_EOL;
echo 'TRANSLIT : ', iconv("UTF-8", "ISO-8859-1//TRANSLIT", $text), PHP_EOL;
echo 'IGNORE : ', iconv("UTF-8", "ISO-8859-1//IGNORE", $text), PHP_EOL;
echo 'Plain : ', iconv("UTF-8", "ISO-8859-1", $text), PHP_EOL;
?>
1.2.399.1. Specs¶
Short name |
Extensions/Exticonv |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.400. ext/igbinary¶
Extension igbinary.
igbinary is a drop in replacement for the standard php serializer. Instead of time and space consuming textual representation, igbinary stores php data structures in compact binary form.
<?php
$serialized = igbinary_serialize($variable);
$unserialized = igbinary_unserialize($serialized);
?>
See also igbinary.
1.2.400.1. Specs¶
Short name |
Extensions/Extigbinary |
Rulesets |
|
Exakat since |
1.0.6 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.401. ext/iis¶
Extension IIS Administration.
It provides functions to administrate Microsoft Internet Information Server (IIS).
<?php
$path = iis_get_server_by_path('/path/to/root/folder/')
?>
This extension is available for Windows only.
See also IIS Administration.
1.2.401.1. Specs¶
Short name |
Extensions/Extiis |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.402. ext/imagick¶
Extension Imagick for PHP.
Imagick is a native php extension to create and modify images using the ImageMagick API.
<?php
header('Content-type: image/jpeg');
$image = new Imagick('image.jpg');
// If 0 is provided as a width or height parameter,
// aspect ratio is maintained
$image->thumbnailImage(100, 0);
echo $image;
?>
See also Imagick for PHP and Imagick.
1.2.402.1. Specs¶
Short name |
Extensions/Extimagick |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.403. ext/imap¶
Extension ext/imap.
This extension operate with the IMAP protocol, as well as the NNTP, POP3 and local mailbox access methods.
<?php
$mbox = imap_open('{imap.example.org}', 'username', 'password', OP_HALFOPEN)
or die('can't connect: ' . imap_last_error());
$list = imap_list($mbox, '{imap.example.org}', '*');
if (is_array($list)) {
foreach ($list as $val) {
echo imap_utf7_decode($val) . PHP_EOL;
}
} else {
echo 'imap_list failed: ' . imap_last_error() . PHP_EOL;
}
imap_close($mbox);
?>
See also IMAP.
1.2.403.1. Specs¶
Short name |
Extensions/Extimap |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.404. ext/info¶
PHP Options and Information.
These functions enable you to get a lot of information about PHP itself, e.g. runtime configuration, loaded extensions, version and much more.
<?php
/*
Our php.ini contains the following settings:
display_errors = On
register_globals = Off
post_max_size = 8M
*/
echo 'display_errors = ' . ini_get('display_errors') . "\n";
echo 'register_globals = ' . ini_get('register_globals') . "\n";
echo 'post_max_size = ' . ini_get('post_max_size') . "\n";
echo 'post_max_size+1 = ' . (ini_get('post_max_size')+1) . "\n";
echo 'post_max_size in bytes = ' . return_bytes(ini_get('post_max_size'));
function return_bytes($val) {
$val = trim($val);
$last = strtolower($val[strlen($val)-1]);
switch($last) {
// The 'G' modifier is available since PHP 5.1.0
case 'g':
$val *= 1024;
case 'm':
$val *= 1024;
case 'k':
$val *= 1024;
}
return $val;
}
?>
See also PHP Options And Information.
1.2.404.1. Specs¶
Short name |
Extensions/Extinfo |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.405. ext/inotify¶
Extension inotify.
The Inotify extension gives access to the Linux kernel subsystem that acts to extend filesystems to notice changes to the filesystem, and report those changes to applications.
<?php
// Open an inotify instance
$fd = inotify_init();
// Watch __FILE__ for metadata changes (e.g. mtime)
$watch_descriptor = inotify_add_watch($fd, __FILE__, IN_ATTRIB);
// generate an event
touch(__FILE__);
// Read events
$events = inotify_read($fd);
print_r($events);
// The following methods allows to use inotify functions without blocking on inotify_read():
// - Using stream_select() on $fd:
$read = array($fd);
$write = null;
$except = null;
stream_select($read,$write,$except,0);
// - Using stream_set_blocking() on $fd
stream_set_blocking($fd, 0);
inotify_read($fd); // Does no block, and return false if no events are pending
// - Using inotify_queue_len() to check if event queue is not empty
$queue_len = inotify_queue_len($fd); // If > 0, inotify_read() will not block
// Stop watching __FILE__ for metadata changes
inotify_rm_watch($fd, $watch_descriptor);
// Close the inotify instance
// This may have closed all watches if this was not already done
fclose($fd);
?>
See also ext/inotify manual and inotify.
1.2.405.1. Specs¶
Short name |
Extensions/Extinotify |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.406. ext/intl¶
Extension international.
Internationalization extension (further is referred as Intl) is a wrapper for ICU library, enabling PHP programmers to perform various locale-aware operations including but not limited to formatting, transliteration, encoding conversion, calendar operations, UCA-conformant collation, locating text boundaries and working with locale identifiers, timezones and graphemes.
<?php
$coll = new Collator('en_US');
$al = $coll->getLocale(Locale::ACTUAL_LOCALE);
echo Actual locale: $al\n;
$formatter = new NumberFormatter('en_US', NumberFormatter::DECIMAL);
echo $formatter->format(1234567);
?>
See also Internationalization Functions.
1.2.406.1. Specs¶
Short name |
Extensions/Extintl |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.407. ext/json¶
Extension JSON.
This extension implements the JavaScript Object Notation (JSON) data-interchange format. PHP implements a superset of JSON as specified in the original RFC 7159.
<?php
$arr = array('a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5);
echo json_encode($arr);
?>
See also JavaScript Object Notation and JSON.
1.2.407.1. Specs¶
Short name |
Extensions/Extjson |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.408. ext/judy¶
The Judy extension.
PHP Judy is a PECL extension for the Judy C library implementing dynamic sparse arrays.
<?php
$judy = new Judy(Judy::BITSET);
if ($judy->getType() === judy_type($judy) &&
$judy->getType() === Judy::BITSET) {
echo 'Judy BITSET type OK'.PHP_EOL;
} else {
echo 'Judy BITSET type check fail'.PHP_EOL;
}
unset($judy);
?>
See also php-judy.
1.2.408.1. Specs¶
Short name |
Extensions/Extjudy |
Rulesets |
|
Exakat since |
0.11.6 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.409. ext/kdm5¶
Extension kdm5 : Kerberos V .
These package allows you to access Kerberos V administration servers. You can create, modify, and delete Kerberos V principals and policies.
<?php
// Extracted from the PHP Manual
$handle = kadm5_init_with_password(afs-1, GONICUS.LOCAL, admin/admin, password);
print <h1>get_principals</h1>\n;
$principals = kadm5_get_principals($handle);
for( $i=0; $i<count($principals); $i++)
print $principals[$i]<br>\n;
print <h1>get_policies</h1>\n;
$policies = kadm5_get_policies($handle);
for( $i=0; $i<count($policies); $i++)
print $policies[$i]<br>\n;
print <h1>get_principal burbach@GONICUS.LOCAL</h1>\n;
$options = kadm5_get_principal($handle, burbach@GONICUS.LOCAL );
$keys = array_keys($options);
for( $i=0; $i<count($keys); $i++) {
$value = $options[$keys[$i]];
print $keys[$i]: $value<br>\n;
}
$options = array(KADM5_PRINC_EXPIRE_TIME => 0);
kadm5_modify_principal($handle, burbach@GONICUS.LOCAL, $options);
kadm5_destroy($handle);
?>
See also Kerberos V and Kerberos: The Network Authentication Protocol.
1.2.409.1. Specs¶
Short name |
Extensions/Extkdm5 |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.410. ext/lapack¶
Extension Lapack. LAPACK provides routines for solving systems of simultaneous linear equations, least-squares solutions of linear systems of equations, eigenvalue problems, and singular value problems.
<?php
$a = array(
array( 1.44, -7.84, -4.39, 4.53),
array(-9.96, -0.28, -3.24, 3.83),
array(-7.55, 3.24, 6.27, -6.64),
array( 8.34, 8.09, 5.28, 2.06),
array( 7.08, 2.52, 0.74, -2.47),
array(-5.45, -5.70, -1.19, 4.70),
);
$b = array(
array( 8.58, 9.35),
array( 8.26, -4.43),
array( 8.48, -0.70),
array(-5.28, -0.26),
array( 5.72, -7.36),
array( 8.93, -2.52),
);
$result = Lapack::leastSquaresByFactorisation($a, $b);
?>
See also Lapack and php-lapack.
1.2.410.1. Specs¶
Short name |
Extensions/Extlapack |
Rulesets |
|
Exakat since |
0.12.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.411. ext/ldap¶
Extension ext/ldap.
LDAP is the Lightweight Directory Access Protocol, and is a protocol used to access ‘Directory Servers’. The Directory is a special kind of database that holds information in a tree structure.
<?php
// basic sequence with LDAP is connect, bind, search, interpret search
// result, close connection
echo '<h3>LDAP query test</h3>';
echo 'Connecting ...';
$ds=ldap_connect('localhost'); // must be a valid LDAP server!
echo 'connect result is ' . $ds . '<br />';
if ($ds) {
echo 'Binding ...';
$r=ldap_bind($ds); // this is an 'anonymous' bind, typically
// read-only access
echo 'Bind result is ' . $r . '<br />';
echo 'Searching for (sn=S*) ...';
// Search surname entry
$sr=ldap_search($ds, 'o=My Company, c=US', 'sn=S*');
echo 'Search result is ' . $sr . '<br />';
echo 'Number of entries returned is ' . ldap_count_entries($ds, $sr) . '<br />';
echo 'Getting entries ...<p>';
$info = ldap_get_entries($ds, $sr);
echo 'Data for ' . $info['count'] . ' items returned:<p>';
for ($i=0; $i<$info['count']; $i++) {
echo 'dn is: ' . $info[$i]['dn'] . '<br />';
echo 'first cn entry is: ' . $info[$i]['cn'][0] . '<br />';
echo 'first email entry is: ' . $info[$i]['mail'][0] . '<br /><hr />';
}
echo 'Closing connection';
ldap_close($ds);
} else {
echo '<h4>Unable to connect to LDAP server</h4>';
}
?>
See also Lightweight `Directory Access Protocol <https://www.php.net/manual/en/book.ldap.php>`_.
1.2.411.1. Specs¶
Short name |
Extensions/Extldap |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.412. ext/leveldb¶
PHP Binding for LevelDB.
LevelDB is a fast key-value storage library written at Google that provides an ordered mapping from string keys to string values.
<?php
$db = new LevelDB($leveldb_path);
$batch = new LevelDBWriteBatch();
$batch->set('batch_foo', 'batch_bar');
$batch->put('batch_foo2', 'batch_bar2');
$batch->delete('batch_foo');
$db->write($batch);
$batch->clear();
$batch->delete('batch_foo2');
$batch->set('batch_foo', 'batch again');
?>
See also ext/leveldb on Github and Leveldb.
1.2.412.1. Specs¶
Short name |
Extensions/Extleveldb |
Rulesets |
|
Exakat since |
1.1.7 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.413. ext/libevent¶
Extension libevent.
Libevent is a library that provides a mechanism to execute a callback function when a specific event occurs on a file descriptor or after a timeout has been reached.
<?php
function print_line($fd, $events, $arg)
{
static $max_requests = 0;
$max_requests++;
if ($max_requests == 10) {
// exit loop after 10 writes
event_base_loopexit($arg[1]);
}
// print the line
echo fgets($fd);
}
// create base and event
$base = event_base_new();
$event = event_new();
$fd = STDIN;
// set event flags
event_set($event, $fd, EV_READ | EV_PERSIST, 'print_line', array($event, $base));
// set event base
event_base_set($event, $base);
// enable event
event_add($event);
// start event loop
event_base_loop($base);
?>
See also libevent and Libevent ext.
1.2.413.1. Specs¶
Short name |
Extensions/Extlibevent |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
Very high |
Available in |
1.2.414. ext/libsodium¶
Extension for libsodium : in PECL until PHP 7.2, and in core ever since.
The Sodium crypto library (libsodium) is a modern, easy-to-use software library for encryption, decryption, signatures, password hashing and more.
Sodium supports a variety of compilers and operating systems, including Windows (with MinGW or Visual Studio, x86 and x64), iOS and Android.
The design choices emphasize security, and “magic constants” have clear rationales.
<?php
// Example from the docs : https://paragonie.com/book/pecl-libsodium/read/06-hashing.md#crypto-generichash
// Fast, unkeyed hash function.
// Can be used as a secure replacement for MD5
$h = \Sodium\crypto_generichash('msg');
// Fast, keyed hash function.
// The key can be of any length between \Sodium\CRYPTO_GENERICHASH_KEYBYTES_MIN
// and \Sodium\CRYPTO_GENERICHASH_KEYBYTES_MAX, in bytes.
// \Sodium\CRYPTO_GENERICHASH_KEYBYTES is the recommended length.
$h = \Sodium\crypto_generichash('msg', $key);
// Fast, keyed hash function, with user-chosen output length, in bytes.
// Output length can be between \Sodium\CRYPTO_GENERICHASH_BYTES_MIN and
// \Sodium\CRYPTO_GENERICHASH_BYTES_MAX.
// \Sodium\CRYPTO_GENERICHASH_BYTES is the default length.
$h = \Sodium\crypto_generichash('msg', $key, 64);
?>
See also PHP extension for libsodium and Using Libsodium in PHP Projects.
1.2.414.1. Specs¶
Short name |
Extensions/Extlibsodium |
Rulesets |
|
Exakat since |
0.10.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.415. ext/libxml¶
Extension libxml.
These functions/constants are available as of PHP 5.1.0, and the following core extensions rely on this libxml extension: DOM, libxml, SimpleXML, SOAP, WDDX, XSL, XML, XMLReader, XMLRPC and XMLWriter.
<?php
// $xmlstr is a string, containing a XML document.
$doc = simplexml_load_string($xmlstr);
$xml = explode(PHP_EOL, $xmlstr);
if ($doc === false) {
$errors = libxml_get_errors();
foreach ($errors as $error) {
echo display_xml_error($error, $xml);
}
libxml_clear_errors();
}
function display_xml_error($error, $xml)
{
$return = $xml[$error->line - 1] . PHP_EOL;
$return .= str_repeat('-', $error->column) . '^'.PHP_EOL;
switch ($error->level) {
case LIBXML_ERR_WARNING:
$return .= 'Warning ',$error->code.': ';
break;
case LIBXML_ERR_ERROR:
$return .= 'Error '.$error->code.': ';
break;
case LIBXML_ERR_FATAL:
$return .= 'Fatal Error '.$error->code.': ';
break;
}
$return .= trim($error->message) .
PHP_EOL.' Line: '.$error->line .
PHP_EOL.' Column: '.$error->column;
if ($error->file) {
$return .= "\n File: $error->file";
}
return $return.PHP_EOL.PHP_EOL.'--------------------------------------------'.PHP_EOL.PHP_EOL;
}
?>
See also libxml.
1.2.415.1. Specs¶
Short name |
Extensions/Extlibxml |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.416. ext/lua¶
Extension Lua.
‘Lua is a powerful, fast, light-weight, embeddable scripting language.’ This extension embeds the lua interpreter and offers an OO-API to lua variables and functions.
<?php
$lua = new Lua();
$lua->eval(<<<CODE
print(2);
CODE
);
?>
- See also ext/lua manual and
1.2.416.1. Specs¶
Short name |
Extensions/Extlua |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.417. ext/lzf¶
Extension LZF.
LZF is a very fast compression algorithm, ideal for saving space with only slight speed cost. It can be optimized for speed or space at the time of compilation.
<?php
$compressed = lzf_compress(This is test of LZF extension);
echo base64_encode($compressed);
?>
1.2.417.1. Specs¶
Short name |
Extensions/Extlzf |
Rulesets |
|
Exakat since |
1.3.5 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.418. ext/mail¶
Extension for mail.
The mail() function allows you to send mail.
<?php
// The message
$message = "Line 1\r\nLine 2\r\nLine 3";
// In case any of our lines are larger than 70 characters, we should use wordwrap()
$message = wordwrap($message, 70, "\r\n");
// Send
mail('caffeinated@example.com', 'My Subject', $message);
?>
See also Mail related functions.
1.2.418.1. Specs¶
Short name |
Extensions/Extmail |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.419. ext/mailparse¶
Extension mailparse.
Mailparse is an extension for parsing and working with email messages. It can deal with RFC 822 (MIME) and RFC 2045 (MIME) compliant messages.
<?php
$mail = mailparse_msg_create();
mailparse_msg_parse($mail, $mailInString);
$parts = mailparse_msg_get_structure($mail);
foreach($parts as $part) {
$section = mailparse_msg_get_part($mail, $part);
$info = mailparse_msg_get_part_data($section);
}
?>
See also Mailparse.
1.2.419.1. Specs¶
Short name |
Extensions/Extmailparse |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.420. ext/math¶
Core functions that provides math standard functions.
This is not a real extension : it is a documentation section, that helps sorting the functions.
<?php
echo decbin(12) . PHP_EOL;
echo decbin(26);
?>
See also Mathematical Functions.
1.2.420.1. Specs¶
Short name |
Extensions/Extmath |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.421. ext/mbstring¶
Extension
ext/mbstring.
mbstring provides multibyte specific string functions that help you deal with multibyte encodings in PHP.
<?php
/* Convert internal character encoding to SJIS */
$str = mb_convert_encoding($str, "SJIS");
/* Convert EUC-JP to UTF-7 */
$str = mb_convert_encoding($str, "UTF-7", "EUC-JP");
/* Auto detect encoding from JIS, eucjp-win, sjis-win, then convert str to UCS-2LE */
$str = mb_convert_encoding($str, "UCS-2LE", "JIS, eucjp-win, sjis-win");
/* "auto" is expanded to "ASCII,JIS,UTF-8,EUC-JP,SJIS" */
$str = mb_convert_encoding($str, "EUC-JP", "auto");
?>
See also Mbstring.
1.2.421.1. Specs¶
Short name |
Extensions/Extmbstring |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.422. ext/mcrypt¶
Extension for mcrypt.
This extension has been deprecated as of PHP 7.1.0 and moved to PECL as of PHP 7.2.0.
This is an interface to the mcrypt library, which supports a wide variety of block algorithms such as DES, TripleDES, Blowfish (default), 3-WAY, SAFER-SK64, SAFER-SK128, TWOFISH, TEA, RC2 and GOST in CBC, OFB, CFB and ECB cipher modes. Additionally, it supports RC6 and IDEA which are considered ‘non-free’. CFB/OFB are 8bit by default.
<?php
# --- ENCRYPTION ---
# the key should be random binary, use scrypt, bcrypt or PBKDF2 to
# convert a string into a key
# key is specified using hexadecimal
$key = pack('H*', 'bcb04b7e103a0cd8b54763051cef08bc55abe029fdebae5e1d417e2ffb2a00a3');
# show key size use either 16, 24 or 32 byte keys for AES-128, 192
# and 256 respectively
$key_size = strlen($key);
echo 'Key size: ' . $key_size . PHP_EOL;
$plaintext = 'This string was AES-256 / CBC / ZeroBytePadding encrypted.';
# create a random IV to use with CBC encoding
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
# creates a cipher text compatible with AES (Rijndael block size = 128)
# to keep the text confidential
# only suitable for encoded input that never ends with value 00h
# (because of default zero padding)
$ciphertext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key,
$plaintext, MCRYPT_MODE_CBC, $iv);
# prepend the IV for it to be available for decryption
$ciphertext = $iv . $ciphertext;
# encode the resulting cipher text so it can be represented by a string
$ciphertext_base64 = base64_encode($ciphertext);
echo $ciphertext_base64 . PHP_EOL;
# === WARNING ===
# Resulting cipher text has no integrity or authenticity added
# and is not protected against padding oracle attacks.
# --- DECRYPTION ---
$ciphertext_dec = base64_decode($ciphertext_base64);
# retrieves the IV, iv_size should be created using mcrypt_get_iv_size()
$iv_dec = substr($ciphertext_dec, 0, $iv_size);
# retrieves the cipher text (everything except the $iv_size in the front)
$ciphertext_dec = substr($ciphertext_dec, $iv_size);
# may remove 00h valued characters from end of plain text
$plaintext_dec = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key,
$ciphertext_dec, MCRYPT_MODE_CBC, $iv_dec);
echo $plaintext_dec . PHP_EOL;
?>
See also extension mcrypt and mcrypt.
1.2.422.1. Specs¶
Short name |
Extensions/Extmcrypt |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.423. ext/memcache¶
Extension Memcache.
Memcache module provides handy procedural and object oriented interface to memcached, highly effective caching daemon, which was especially designed to decrease database load in dynamic web applications.
<?php
$memcache = new Memcache;
$memcache->connect('localhost', 11211) or die ('Could not connect');
$version = $memcache->getVersion();
echo 'Server\'s version: '.$version.'<br/>';
$tmp_object = new stdClass;
$tmp_object->str_attr = 'test';
$tmp_object->int_attr = 123;
$memcache->set('key', $tmp_object, false, 10) or die ('Failed to save data at the server');
echo 'Store data in the cache (data will expire in 10 seconds)<br/>';
$get_result = $memcache->get('key');
echo 'Data from the cache:<br/>';
var_dump($get_result);
?>
See also Memcache on PHP and memcached.
1.2.423.1. Specs¶
Short name |
Extensions/Extmemcache |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.424. ext/memcached¶
Extension ext-memcached.
This extension uses the libmemcached library to provide an API for communicating with memcached servers. It also provides a session handler (memcached).
<?php
$m = new Memcached();
$m->addServer('localhost', 11211);
$m->set('foo', 100);
var_dump($m->get('foo'));
?>
See also ext/memcached manual and memcached.
1.2.424.1. Specs¶
Short name |
Extensions/Extmemcached |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
Very high |
Available in |
1.2.425. ext/mhash¶
Extension mhash (obsolete since PHP 5.3.0).
This extension provides functions, intended to work with mhash.
<?php
$input = 'what do ya want for nothing?';
$hash = mhash(MHASH_MD5, $input);
echo 'The hash is ' . bin2hex($hash) . '<br />'.PHP_EOL;
$hash = mhash(MHASH_MD5, $input, 'Jefe');
echo 'The hmac is ' . bin2hex($hash) . '<br />'.PHP_EOL;
?>
See also Extension mhash.
1.2.425.1. Specs¶
Short name |
Extensions/Extmhash |
Rulesets |
|
Exakat since |
0.9.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.426. ext/ming¶
Extension ext/ming, to create swf files with PHP.
Ming is an open-source (LGPL) library which allows you to create SWF (‘Flash’) format movies.
<?php
$s = new SWFShape();
$f = $s->addFill(0xff, 0, 0);
$s->setRightFill($f);
$s->movePenTo(-500, -500);
$s->drawLineTo(500, -500);
$s->drawLineTo(500, 500);
$s->drawLineTo(-500, 500);
$s->drawLineTo(-500, -500);
$p = new SWFSprite();
$i = $p->add($s);
$i->setDepth(1);
$p->nextFrame();
for ($n=0; $n<5; ++$n) {
$i->rotate(-15);
$p->nextFrame();
}
$m = new SWFMovie();
$m->setBackground(0xff, 0xff, 0xff);
$m->setDimension(6000, 4000);
$i = $m->add($p);
$i->setDepth(1);
$i->moveTo(-500,2000);
$i->setName('box');
$m->add(new SWFAction('/box.x += 3;'));
$m->nextFrame();
$m->add(new SWFAction('gotoFrame(0); play();'));
$m->nextFrame();
header('Content-type: application/x-shockwave-flash');
$m->output();
?>
See also Ming (flash) and Ming.
1.2.426.1. Specs¶
Short name |
Extensions/Extming |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.427. ext/mongo¶
Extension MongoDB driver (legacy).
<?php
// connect
$m = new MongoClient();
// select a database
$db = $m->comedy;
// select a collection (analogous to a relational database\'s table)
$collection = $db->cartoons;
// add a record
$document = array( 'title' => 'Calvin and Hobbes', 'author' => 'Bill Watterson' );
$collection->insert($document);
// add another record, with a different 'shape'
$document = array( 'title' => 'XKCD', 'online' => true );
$collection->insert($document);
// find everything in the collection
$cursor = $collection->find();
// iterate through the results
foreach ($cursor as $document) {
echo $document['title'] . PHP_EOL;
}
?>
Note : this is not the MongoDB driver. This is the legacy extension.
See also ext/mongo manual and MongdDb.
1.2.427.1. Specs¶
Short name |
Extensions/Extmongo |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.428. ext/mongodb¶
Extension MongoDb.
Do not mistake with extension Mongo, the previous version.
Mongodb driver supports both PHP and HHVM and is developed atop the libmongoc and libbson libraries.
<?php
require 'vendor/autoload.php'; // include Composer's autoloader
$client = new MongoDB\Client(mongodb://localhost:27017);
$collection = $client->demo->beers;
$result = $collection->insertOne( [ 'name' => 'Hinterland', 'brewery' => 'BrewDog' ] );
echo Inserted with Object ID {$result->getInsertedId()};
?>
See also MongoDB driver.
1.2.428.1. Specs¶
Short name |
Extensions/Extmongodb |
Rulesets |
|
Exakat since |
0.9.5 |
PHP Version |
7.0+ |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.429. ext/msgpack¶
Extension msgPack.
This extension provide API for communicating with MessagePack serialization.
<?php
$serialized = msgpack_serialize(array('a' => true, 'b' => 4));
$unserialized = msgpack_unserialize($serialized);
?>
See also msgpack for PHP and MessagePack.
1.2.429.1. Specs¶
Short name |
Extensions/Extmsgpack |
Rulesets |
|
Exakat since |
1.3.5 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.430. ext/mssql¶
Extension MSSQL, Microsoft SQL Server.
These functions allow you to access MS SQL Server database.
<?php
// Connect to MSSQL
$link = mssql_connect('KALLESPC\SQLEXPRESS', 'sa', 'phpfi');
if (!$link || !mssql_select_db('php', $link)) {
die('Unable to connect or select database!');
}
// Do a simple query, select the version of
// MSSQL and print it.
$version = mssql_query('SELECT @@VERSION');
$row = mssql_fetch_array($version);
echo $row[0];
// Clean up
mssql_free_result($version);
?>
See also Microsoft SQL Server and Microsoft PHP Driver for SQL Server.
1.2.430.1. Specs¶
Short name |
Extensions/Extmssql |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.431. ext/mysql¶
Extension for MySQL (Original MySQL API).
This extension is deprecated as of PHP 5.5.0, and has been removed as of PHP 7.0.0. Instead, either the mysqli or PDO_MySQL extension should be used. See also the MySQL API Overview for further help while choosing a MySQL API. .. code-block:: php <?php $result = mysql_query(‘SELECT * WHERE 1=1’); if (!$result) { die(‘Invalid query: ‘ . mysql_error()); } ?> See also Original MySQL API and MySQL.
1.2.431.1. Specs¶
Short name |
Extensions/Extmysql |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
7.0- |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.432. ext/mysqli¶
Extension mysqli for MySQL.
The mysqli extension allows you to access the functionality provided by MySQL 4.1 and above.
<?php
$mysqli = new mysqli('localhost', 'my_user', 'my_password', 'world');
/* check connection */
if (mysqli_connect_errno()) {
printf('Connect failed: %s\n', mysqli_connect_error());
exit();
}
$city = 'Amersfoort';
/* create a prepared statement */
if ($stmt = $mysqli->prepare('SELECT District FROM City WHERE Name=?')) {
/* bind parameters for markers */
$stmt->bind_param('s', $city);
/* execute query */
$stmt->execute();
/* bind result variables */
$stmt->bind_result($district);
/* fetch value */
$stmt->fetch();
printf('%s is in district %s\n', $city, $district);
/* close statement */
$stmt->close();
}
/* close connection */
$mysqli->close();
?>
See also MySQL Improved Extension <https://www.php.net/manual/en/book.`mysqli.php>`_ and MySQL.
1.2.432.1. Specs¶
Short name |
Extensions/Extmysqli |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.433. ext/ncurses¶
Extension ncurses (CLI).
ncurses (new curses) is a free software emulation of curses in System V Rel 4.0 (and above).
<?php
ncurses_init();
ncurses_start_color();
ncurses_init_pair(1, NCURSES_COLOR_GREEN, NCURSES_COLOR_BLACK);
ncurses_init_pair(2, NCURSES_COLOR_RED, NCURSES_COLOR_BLACK);
ncurses_init_pair(3, NCURSES_COLOR_WHITE, NCURSES_COLOR_BLACK);
ncurses_color_set(1);
ncurses_addstr('OK ');
ncurses_color_set(3);
ncurses_addstr('Success!'.PHP_EOL);
ncurses_color_set(2);
ncurses_addstr('FAIL ');
ncurses_color_set(3);
ncurses_addstr('Success!'.PHP_EOL);
?>
See also Ncurses Terminal Screen Control and Ncurses.
1.2.433.1. Specs¶
Short name |
Extensions/Extncurses |
Rulesets |
|
Exakat since |
0.9.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.434. ext/newt¶
Newt PHP CLI extension.
This is a PHP language extension for RedHat Newt library, a terminal-based window and widget library for writing applications with user friendly interface.
<?php
newt_init ();
newt_cls ();
newt_draw_root_text (0, 0, Test Mode Setup Utility 1.12);
newt_push_help_line (null);
newt_get_screen_size ($rows, $cols);
newt_open_window ($rows/2-17, $cols/2-10, 34, 17, Choose a Tool);
$form = newt_form ();
$list = newt_listbox (3, 2, 10);
foreach (array (
Authentication configuration,
Firewall configuration,
Mouse configuration,
Network configuration,
Printer configuration,
System services) as $l_item)
{
newt_listbox_add_entry ($list, $l_item, $l_item);
}
$b1 = newt_button (5, 12, Run Tool);
$b2 = newt_button (21, 12, Quit);
newt_form_add_component ($form, $list);
newt_form_add_components ($form, array($b1, $b2));
newt_refresh ();
newt_run_form ($form);
newt_pop_window ();
newt_pop_help_line ();
newt_finished ();
newt_form_destroy ($form);
?>
See also Newt.
1.2.434.1. Specs¶
Short name |
Extensions/Extnewt |
Rulesets |
|
Exakat since |
0.9.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.435. ext/nsapi¶
NSAPI specific functions calls.
These functions are only available when running PHP as a NSAPI module in Netscape/iPlanet/Sun webservers.
<?php
// This scripts depends on ext/nsapi
if (ini_get('nsapi.read_timeout') < 60) {
doSomething();
}
?>
See also Sun, iPlanet and Netscape servers on Sun Solaris.
1.2.435.1. Specs¶
Short name |
Extensions/Extnsapi |
Rulesets |
|
Exakat since |
0.9.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.436. ext/ob¶
Extension Output Buffering Control.
The Output Control functions allow you to control when output is sent from the script.
<?php
ob_start();
echo Hello\n;
setcookie(cookiename, cookiedata);
ob_end_flush();
?>
See also Output Buffering Control.
1.2.436.1. Specs¶
Short name |
Extensions/Extob |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.437. ext/oci8¶
Extension ext/oci8.
OCI8 gives access Oracle Database 12c, 11g, 10g, 9i and 8i.
<?php
$conn = oci_connect('hr', 'welcome', 'localhost/XE');
if (!$conn) {
$e = oci_error();
trigger_error(htmlentities($e['message'], ENT_QUOTES), E_USER_ERROR);
}
// Prepare the statement
$stid = oci_parse($conn, 'SELECT * FROM departments');
if (!$stid) {
$e = oci_error($conn);
trigger_error(htmlentities($e['message'], ENT_QUOTES), E_USER_ERROR);
}
// Perform the logic of the query
$r = oci_execute($stid);
if (!$r) {
$e = oci_error($stid);
trigger_error(htmlentities($e['message'], ENT_QUOTES), E_USER_ERROR);
}
// Fetch the results of the query
print '<table border='1'>' . PHP_EOL;
while ($row = oci_fetch_array($stid, OCI_ASSOC+OCI_RETURN_NULLS)) {
print '<tr>' . PHP_EOL;
foreach ($row as $item) {
print ' <td>' . ($item !== null ? htmlentities($item, ENT_QUOTES) : ' ') . '</td>' . PHP_EOL;
}
print '</tr>' . PHP_EOL;
}
print '</table>' . PHP_EOL;
oci_free_statement($stid);
oci_close($conn);
?>
See also Oracle OCI8 and Oracle.
1.2.437.1. Specs¶
Short name |
Extensions/Extoci8 |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.438. ext/odbc¶
Extension ODBC.
In addition to normal ODBC support, the Unified ODBC functions in PHP allow you to access several databases that have borrowed the semantics of the ODBC API to implement their own API. Instead of maintaining multiple database drivers that were all nearly identical, these drivers have been unified into a single set of ODBC functions.
<?php
$a = 1;
$b = 2;
$c = 3;
$stmt = odbc_prepare($conn, 'CALL myproc(?,?,?)');
$success = odbc_execute($stmt, array($a, $b, $c));
?>
See also ODBC (Unified), Unixodbc and IODBC.
1.2.438.1. Specs¶
Short name |
Extensions/Extodbc |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.439. ext/opcache¶
Extension opcache.
OPcache improves PHP performance by storing precompiled script bytecode in shared memory, thereby removing the need for PHP to load and parse scripts on each request.
<?php
echo opcache_compile_file('/var/www/index.php');
print_r(opcache_get_status());
?>
See also OPcache functions.
1.2.439.1. Specs¶
Short name |
Extensions/Extopcache |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.440. ext/opencensus¶
Extension PHP for OpenCensus :
A stats collection and distributed tracing framework.
<?php
opencensus_trace_begin('root', ['spanId' => '1234']);
opencensus_trace_add_annotation('foo');
opencensus_trace_begin('inner', []);
opencensus_trace_add_annotation('asdf', ['spanId' => '1234']);
opencensus_trace_add_annotation('abc');
opencensus_trace_finish();
opencensus_trace_finish();
$traces = opencensus_trace_list();
echo Number of traces: . count($traces) . \n;
$span = $traces[0];
print_r($span->timeEvents());
$span2 = $traces[1];
print_r($span2->timeEvents());
?>
See also opencensus.
1.2.440.1. Specs¶
Short name |
Extensions/Extopencensus |
Rulesets |
|
Exakat since |
1.1.7 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.441. ext/openssl¶
Extension Openssl.
This extension binds functions of OpenSSL library for symmetric and asymmetric encryption and decryption, PBKDF2, PKCS7, PKCS12, X509 and other cryptographic operations. In addition to that it provides implementation of TLS streams.
<?php
// $data and $signature are assumed to contain the data and the signature
// fetch public key from certificate and ready it
$pubkeyid = openssl_pkey_get_public("file://src/openssl-0.9.6/demos/sign/cert.pem");
// state whether signature is okay or not
$ok = openssl_verify($data, $signature, $pubkeyid);
if ($ok == 1) {
echo "good";
} elseif ($ok == 0) {
echo "bad";
} else {
echo "ugly, error checking signature";
}
// free the key from memory
openssl_free_key($pubkeyid);
?>
See also ext/OpenSSL and OpenSSL.
1.2.441.1. Specs¶
Short name |
Extensions/Extopenssl |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.442. ext/parle¶
Extension Parser and Lexer.
The parle extension provides lexing and parsing facilities. The implementation is based on » Ben Hanson’s libraries and requires a » C++14 capable compiler.
<?php
use Parle\{Token, Lexer, LexerException};
/* name => id */
$token = array(
'EOI' => 0,
'COMMA' => 1,
'CRLF' => 2,
'DECIMAL' => 3,
);
/* id => name */
$token_rev = array_flip($token);
$lex = new Lexer;
$lex->push("[\x2c]", $token['COMMA']);
$lex->push("[\r][\n]", $token['CRLF']);
$lex->push("[\d]+", $token['DECIMAL']);
$lex->build();
$in = 0,1,2\r\n3,42,5\r\n6,77,8\r\n;
$lex->consume($in);
do {
$lex->advance();
$tok = $lex->getToken();
if (Token::UNKNOWN == $tok->id) {
throw new LexerException('Unknown token "'.$tok->value.'" at offset '.$tok->offset.'.');
}
echo 'TOKEN: ', $token_rev[$tok->id], PHP_EOL;
} while (Token::EOI != $tok->id);
?>
See also Parsing and Lexing.
1.2.442.1. Specs¶
Short name |
Extensions/Extparle |
Rulesets |
|
Exakat since |
0.12.12 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.443. ext/parsekit¶
Extension Parsekit.
These functions allow runtime analysis of opcodes compiled from PHP scripts.
<?php
var_dump(parsekit_compile_file('hello_world.php', $errors, PARSEKIT_SIMPLE));
?>
See also Parsekit.
1.2.443.1. Specs¶
Short name |
Extensions/Extparsekit |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.444. ext/password¶
Extension password.
The password hashing API provides an easy to use wrapper around crypt() and some other password hashing algorithms, to make it easy to create and manage passwords in a secure manner.
<?php
// See the password_hash() example to see where this came from.
$hash = '\$2y\$07$BCryptRequires22Chrcte/VlQH0piJtjXl.0t1XkA8pw9dMXTpOq';
if (password_verify('rasmuslerdorf', $hash)) {
echo 'Password is valid!';
} else {
echo 'Invalid password.';
}
?>
See also Password Hashing and crypt man page.
1.2.444.1. Specs¶
Short name |
Extensions/Extpassword |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.445. ext/pcntl¶
Extension for process control.
Process Control support in PHP implements the Unix style of process creation, program execution, signal handling and process termination. Process Control should not be enabled within a web server environment and unexpected results may happen if any Process Control functions are used within a web server environment.
<?php
declare(ticks=1);
$pid = pcntl_fork();
if ($pid == -1) {
die('could not fork');
} else if ($pid) {
exit(); // we are the parent
} else {
// we are the child
}
// detatch from the controlling terminal
if (posix_setsid() == -1) {
die('could not detach from terminal');
}
// setup signal handlers
pcntl_signal(SIGTERM, 'sig_handler');
pcntl_signal(SIGHUP, 'sig_handler');
// loop forever performing tasks
while (1) {
// do something interesting here
}
function sig_handler($signo)
{
switch ($signo) {
case SIGTERM:
// handle shutdown tasks
exit;
break;
case SIGHUP:
// handle restart tasks
break;
default:
// handle all other signals
}
}
?>
See also Process Control.
1.2.445.1. Specs¶
Short name |
Extensions/Extpcntl |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.446. ext/pcov¶
CodeCoverage compatible driver for PHP
A self contained CodeCoverage compatible driver for PHP7
<?php
\pcov\start();
$d = [];
for ($i = 0; $i < 10; $i++) {
$d[] = $i * 42;
}
\pcov\stop();
var_dump(\pcov\collect());
?>
See also PCOV.
1.2.446.1. Specs¶
Short name |
Extensions/Extpcov |
Rulesets |
|
Exakat since |
1.6.5 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.447. ext/pcre¶
Extension ext/pcre. PCRE stands for Perl Compatible Regular Expression. It is a standard PHP extension.
<?php
$zip_code = $_GET['zip'];
// Canadian Zip code H2M 3J1
$zip_ca = '/^([a-zA-Z]\d[a-zA-Z])\ {0,1}(\d[a-zA-Z]\d)$/';
// French Zip code 75017
$zip_fr = '/^\d{5}$/';
// Chinese Zip code 590615
$zip_cn = '/^\d{6}$/';
var_dump(preg_match($_GET['zip']));
?>
See also Regular Expressions (Perl-Compatible).
1.2.447.1. Specs¶
Short name |
Extensions/Extpcre |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.448. ext/pdo¶
Generic extension PDO.
The PHP Data Objects (PDO) extension defines a lightweight, consistent interface for accessing databases in PHP.
<?php
/* Execute a prepared statement by passing an array of values */
$sql = 'SELECT name, colour, calories
FROM fruit
WHERE calories < :calories AND colour = :colour';
$sth = $dbh->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
$sth->execute(array(':calories' => 150, ':colour' => 'red'));
$red = $sth->fetchAll();
$sth->execute(array(':calories' => 175, ':colour' => 'yellow'));
$yellow = $sth->fetchAll();
?>
See also PHP Data Object.
1.2.448.1. Specs¶
Short name |
Extensions/Extpdo |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.449. ext/pgsql¶
Extension PostGreSQL.
PostgreSQL is an open source descendant of this original Berkeley code. It provides SQL92/SQL99 language support, transactions, referential integrity, stored procedures and type extensibility.
<?php
// Connect to a database named 'mary'
$dbconn = pg_connect('dbname=mary');
// Prepare a query for execution
$result = pg_prepare($dbconn, 'my_query', 'SELECT * FROM shops WHERE name = \$1');
// Execute the prepared query. Note that it is not necessary to escape
// the string 'Joe's Widgets' in any way
$result = pg_execute($dbconn, 'my_query', array('Joe\'s Widgets'));
// Execute the same prepared query, this time with a different parameter
$result = pg_execute($dbconn, 'my_query', array('Clothes Clothes Clothes'));
?>
See also PostgreSQL and PostgreSQL: The world’s most advanced open source database.
1.2.449.1. Specs¶
Short name |
Extensions/Extpgsql |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.450. ext/phalcon¶
Extension Phalcon : High Performance PHP Framework.
Phalcon’s autoload examples from the docs : Tutorial 1: Let’s learn by example
<?php
use Phalcon\Loader;
// ...
$loader = new Loader();
$loader->registerDirs(
[
../app/controllers/,
../app/models/,
]
);
$loader->register();
?>
See also PhalconPHP.
1.2.450.1. Specs¶
Short name |
Extensions/Extphalcon |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.451. ext/phar¶
Extension phar.
The phar extension provides a way to put entire PHP applications into a single file called a phar (PHP Archive) for easy distribution and installation.
<?php
try {
$p = new Phar('/path/to/my.phar', 0, 'my.phar');
$p['myfile.txt'] = 'hi';
$file = $p['myfile.txt'];
var_dump($file->isCompressed(Phar::BZ2));
$p['myfile.txt']->compress(Phar::BZ2);
var_dump($file->isCompressed(Phar::BZ2));
} catch (Exception $e) {
echo 'Create/modify operations on my.phar failed: ', $e;
}
?>
See also phar.
1.2.451.1. Specs¶
Short name |
Extensions/Extphar |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.452. ext/posix¶
Extension POSIX.
Ext/posix contains an interface to those functions defined in the IEEE 1003.1 (POSIX.1) standards document which are not accessible through other means.
<?php
posix_kill(999459,SIGKILL);
echo 'Your error returned was '.posix_get_last_error(); //Your error was ___
?>
1.2.452.1. Specs¶
Short name |
Extensions/Extposix |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.453. ext/proctitle¶
Extension proctitle.
This extension allows changing the current process’, and thread, name on Linux and *BSD systems. This is useful when using pcntl_fork() to identify running processes in process list
<?php
setproctitle('myscript');
?>
See also proctitle.
1.2.453.1. Specs¶
Short name |
Extensions/Extproctitle |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.454. ext/pspell¶
Extension pspell.
These functions allow you to check the spelling of a word and offer suggestions.
<?php
$pspell_link = pspell_new('en');
if (pspell_check($pspell_link, 'testt')) {
echo 'This is a valid spelling';
} else {
echo 'Sorry, wrong spelling';
}
?>
1.2.454.1. Specs¶
Short name |
Extensions/Extpspell |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.455. ext/psr¶
Extension PSR : PHP Standards Recommendations.
This PHP extension provides the interfaces from the PSR standards as established by the PHP-FIG group. You can use interfaces provided by this extension in another extension easily - see this example.
Currently supported PSR :
PSR-3 - psr/http-message
PSR-11 - psr/container
PSR-13 - psr/link
PSR-15 - psr/http-server
PSR-16 - psr/simple-cache
PSR-17 - psr/http-factory
<?php
// Example from the tests, for Cache (PSR-6)
use Psr\Cache\CacheException;
class MyCacheException extends Exception implements CacheException {}
$ex = new MyCacheException('test');
var_dump($ex instanceof CacheException);
var_dump($ex instanceof Exception);
try {
throw $ex;
} catch( CacheException $e ) {
var_dump($e->getMessage());
}
?>
1.2.455.1. Specs¶
Short name |
Extensions/Extpsr |
Rulesets |
|
Exakat since |
1.5.2 |
PHP Version |
With PHP 7.0 and more recent |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
Very high |
Available in |
1.2.456. ext/rar¶
Extension RAR.
Rar is a powerful and effective archiver created by Eugene Roshal. This extension gives you possibility to read Rar archives but doesn’t support writing Rar archives, because this is not supported by the UnRar library and is directly prohibited by its license.
<?php
$arch = RarArchive::open(example.rar);
if ($arch === FALSE)
die(Cannot open example.rar);
$entries = $arch->getEntries();
if ($entries === FALSE)
die(Cannot retrieve entries);
?>
See also Rar archiving and rarlabs.
1.2.456.1. Specs¶
Short name |
Extensions/Extrar |
Rulesets |
|
Exakat since |
0.8.7 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.457. ext/rdkafka¶
Extension for RDkafka.
PHP-rdkafka is a thin librdkafka binding providing a working PHP 5 / PHP 7 Kafka 0.8 / 0.9 / 0.10 client.
<?php
$rk = new RdKafka\Producer();
$rk->setLogLevel(LOG_DEBUG);
$rk->addBrokers(10.0.0.1,10.0.0.2);
?>
See also Kafka client for PHP.
1.2.457.1. Specs¶
Short name |
Extensions/Extrdkafka |
Rulesets |
|
Exakat since |
0.12.8 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.458. ext/readline¶
Extension readline.
The readline functions implement an interface to the GNU Readline library. These are functions that provide editable command lines.
<?php
//get 3 commands from user
for ($i=0; $i < 3; $i++) {
$line = readline("Command: ");
readline_add_history($line);
}
//dump history
print_r(readline_list_history());
//dump variables
print_r(readline_info());
?>
See also ext/readline and The GNU Readline Library.
1.2.458.1. Specs¶
Short name |
Extensions/Extreadline |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.459. ext/recode¶
Extension GNU Recode.
This module contains an interface to the GNU Recode library. The GNU Recode library converts files between various coded character sets and surface encodings.
<?php
echo recode_string('us..flat', 'The following character has a diacritical mark: á');
?>
This extension is not available on Windows.
See also ext/recode and Recode.
1.2.459.1. Specs¶
Short name |
Extensions/Extrecode |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.460. ext/redis¶
Extension ext/redis.
The phpredis extension provides an API for communicating with the Redis key-value store.
<?php
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$redis->setOption(Redis::OPT_SERIALIZER, Redis::SERIALIZER_NONE); // don't serialize data
$redis->setOption(Redis::OPT_SERIALIZER, Redis::SERIALIZER_PHP); // use built-in serialize/unserialize
$redis->setOption(Redis::OPT_SERIALIZER, Redis::SERIALIZER_IGBINARY); // use igBinary serialize/unserialize
$redis->setOption(Redis::OPT_PREFIX, 'myAppName:'); // use custom prefix on all keys
/* Options for the SCAN family of commands, indicating whether to abstract
empty results from the user. If set to SCAN_NORETRY (the default), phpredis
will just issue one SCAN command at a time, sometimes returning an empty
array of results. If set to SCAN_RETRY, phpredis will retry the scan command
until keys come back OR Redis returns an iterator of zero
*/
$redis->setOption(Redis::OPT_SCAN, Redis::SCAN_NORETRY);
$redis->setOption(Redis::OPT_SCAN, Redis::SCAN_RETRY);
?>
See also A PHP extension for Redis and Redis.
1.2.460.1. Specs¶
Short name |
Extensions/Extredis |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.461. ext/reflection¶
Extension Reflection.
PHP comes with a complete reflection API that adds the ability to reverse-engineer classes, interfaces, functions, methods and extensions. Additionally, the reflection API offers ways to retrieve doc comments for functions, classes and methods.
<?php
/**
* A simple counter
*
* @return int
*/
function counter1()
{
static $c = 0;
return ++$c;
}
/**
* Another simple counter
*
* @return int
*/
$counter2 = function()
{
static $d = 0;
return ++$d;
};
function dumpReflectionFunction($func)
{
// Print out basic information
printf(
PHP_EOL.'===> The %s function '%s''.PHP_EOL.
' declared in %s'.PHP_EOL.
' lines %d to %d'.PHP_EOL,
$func->isInternal() ? 'internal' : 'user-defined',
$func->getName(),
$func->getFileName(),
$func->getStartLine(),
$func->getEndline()
);
// Print documentation comment
printf('---> Documentation:'.PHP_EOL.' %s',PHP_EOL, var_export($func->getDocComment(), 1));
// Print static variables if existant
if ($statics = $func->getStaticVariables())
{
printf('---> Static variables: %s',PHP_EOL, var_export($statics, 1));
}
}
// Create an instance of the ReflectionFunction class
dumpReflectionFunction(new ReflectionFunction('counter1'));
dumpReflectionFunction(new ReflectionFunction($counter2));
?>
See also Reflection.
1.2.461.1. Specs¶
Short name |
Extensions/Extreflection |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.462. ext/runkit¶
Extension Runkit.
The runkit extension provides means to modify constants, user-defined functions, and user-defined classes. It also provides for custom superglobal variables and embeddable sub-interpreters via sandboxing.
<?php
class Example {
function foo() {
echo 'foo!'.PHP_EOL;
}
}
// create an Example object
$e = new Example();
// Add a new public method
runkit_method_add(
'Example',
'add',
'$num1, $num2',
'return $num1 + $num2;',
RUNKIT_ACC_PUBLIC
);
// add 12 + 4
echo $e->add(12, 4);
?>
See also runkit.
1.2.462.1. Specs¶
Short name |
Extensions/Extrunkit |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.463. ext/sdl¶
Extensions ext/sdl.
Simple DirectMedia Layer (SDL) is a cross-platform software development library designed to provide a hardware abstraction layer for computer multimedia hardware components.
<?php
/**
* Example of how to change screen properties such as title, icon or state using the PHP-SDL extension.
*
* @author Santiago Lizardo <santiagolizardo@php.net>
*/
require 'common.php';
SDL_Init( SDL_INIT_VIDEO );
$screen = SDL_SetVideoMode( 640, 480, 16, SDL_HWSURFACE );
if( null == $screen )
{
fprintf( STDERR, 'Error: %s' . PHP_EOL, SDL_GetError() );
}
for( $i = 3; $i > 0; $i-- )
{
SDL_WM_SetCaption( Switching to fullscreen mode in $i seconds..., null );
SDL_Delay( 1000 );
}
SDL_WM_ToggleFullscreen( $screen );
SDL_Delay( 3000 );
SDL_WM_ToggleFullscreen( $screen );
SDL_WM_SetCaption( Back from fullscreen mode. Quitting in 2 seconds..., null );
SDL_Delay( 2000 );
SDL_FreeSurface( $screen );
SDL_Quit();
?>
See also phpsdl, Simple DirectMedia Layer and About SDL.
1.2.463.1. Specs¶
Short name |
Extensions/Extsdl |
Rulesets |
|
Exakat since |
1.5.6 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.464. ext/seaslog¶
Extension Seaslog.
An effective,fast,stable log extension for PHP.
<?php
$basePath_1 = SeasLog::getBasePath();
SeasLog::setBasePath('/log/base_test');
$basePath_2 = SeasLog::getBasePath();
var_dump($basePath_1,$basePath_2);
/*
string(19) /log/seaslog-ciogao
string(14) /log/base_test
*/
$lastLogger_1 = SeasLog::getLastLogger();
SeasLog::setLogger('testModule/app1');
$lastLogger_2 = SeasLog::getLastLogger();
var_dump($lastLogger_1,$lastLogger_2);
/*
string(7) default
string(15) testModule/app1
*/
?>
See also ext/SeasLog on Github, and SeasLog.
1.2.464.1. Specs¶
Short name |
Extensions/Extseaslog |
Rulesets |
|
Exakat since |
1.4.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.465. ext/sem¶
Extension Semaphore, Shared Memory and IPC.
This module provides wrappers for the System V IPC family of functions. It includes semaphores, shared memory and inter-process messaging (IPC).
<?php
$key = ftok(__FILE__,'a');
$semaphore = sem_get($key);
sem_acquire($semaphore);
sem_release($semaphore);
sem_remove($semaphore);
?>
See also Semaphore, Shared Memory and IPC.
1.2.465.1. Specs¶
Short name |
Extensions/Extsem |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.466. ext/session¶
Extension ext/session.
Session support in PHP consists of a way to preserve certain data across subsequent accesses.
<?php
session_start();
if (!isset($_SESSION['count'])) {
$_SESSION['count'] = 0;
} else {
$_SESSION['count']++;
}
?>
See also Session.
1.2.466.1. Specs¶
Short name |
Extensions/Extsession |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.467. ext/shmop¶
Extension ext/shmop.
Shmop is an easy to use set of functions that allows PHP to read, write, create and delete Unix shared memory segments.
<?php
// Create a temporary file and return its path
$tmp = tempnam('/tmp', 'PHP');
// Get the file token key
$key = ftok($tmp, 'a');
// Attach the SHM resource, notice the cast afterwards
$id = shm_attach($key);
if ($id === false) {
die('Unable to create the shared memory segment');
}
// Cast to integer, since prior to PHP 5.3.0 the resource id
// is returned which can be exposed when casting a resource
// to an integer
$id = (integer) $id;
?>
See also Semaphore, Shared Memory and IPC.
1.2.467.1. Specs¶
Short name |
Extensions/Extshmop |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.468. ext/simplexml¶
Extension
SimpleXML.
The SimpleXML extension provides a very simple and easily usable toolset to convert XML to an object that can be processed with normal property selectors and array iterators.
<?php
$xml = <<<'XML'
<?xml version='1.0' standalone='yes' ? >
<movies>
<movie>
<title>PHP: Behind the Parser</title>
<characters>
<character>
<name>Ms. Coder</name>
<actor>Onlivia Actora</actor>
</character>
<character>
<name>Mr. Coder</name>
<actor>El ActÓr</actor>
</character>
</characters>
<plot>
So, this language. It's like, a programming language. Or is it a
scripting language? All is revealed in this thrilling horror spoof
of a documentary.
</plot>
<great-lines>
<line>PHP solves all my web problems</line>
</great-lines>
<rating type="thumbs">7</rating>
<rating type="stars">5</rating>
</movie>
</movies>
XML;
$movies = new SimpleXMLElement($xml);
echo $movies->movie[0]->plot;
?>
See also SimpleXML.
1.2.468.1. Specs¶
Short name |
Extensions/Extsimplexml |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.469. ext/snmp¶
Extension SNMP.
The SNMP extension provides a very simple and easily usable toolset for managing remote devices via the Simple Network Management Protocol.
<?php
$nameOfSecondInterface = snmp3_get('localhost', 'james', 'authPriv', 'SHA', 'secret007', 'AES', 'secret007', 'IF-MIB::ifName.2');
?>
See also Net `SNMP <http://www.net-snmp.org/>`_ and SNMP.
1.2.469.1. Specs¶
Short name |
Extensions/Extsnmp |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.470. ext/soap¶
Extension SOAP.
The SOAP extension can be used to write SOAP Servers and Clients. It supports subsets of » SOAP 1.1, » SOAP 1.2 and » WSDL 1.1 specifications.
<?php
$client = new SoapClient("some.wsdl");
$client = new SoapClient("some.wsdl", array('soap_version' => SOAP_1_2));
$client = new SoapClient("some.wsdl", array('login' => "some_name",
'password' => "some_password"));
?>
See also SOAP and SOAP specifications.
1.2.470.1. Specs¶
Short name |
Extensions/Extsoap |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.471. ext/sockets¶
Extension socket.
The socket extension implements a low-level interface to the socket communication functions based on the popular BSD sockets, providing the possibility to act as a socket server as well as a client.
<?php
//Example #2 Socket example: Simple TCP/IP client
//From the PHP manual
error_reporting(E_ALL);
echo "<h2>TCP/IP Connection</h2>\n";
/* Get the port for the WWW service. */
$service_port = getservbyname('www', 'tcp');
/* Get the IP address for the target host. */
$address = gethostbyname('www.example.com');
/* Create a TCP/IP socket. */
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if ($socket === false) {
echo 'socket_create() failed: reason: ' . socket_strerror(socket_last_error()) . PHP_EOL;
} else {
echo 'OK.'.PHP_EOL;
}
echo 'Attempting to connect to '$address' on port '$service_port'...';
$result = socket_connect($socket, $address, $service_port);
if ($result === false) {
echo 'socket_connect() failed.\nReason: ($result) ' . socket_strerror(socket_last_error($socket)) . '\n';
} else {
echo 'OK.'.PHP_EOL;
}
$in = ""HEAD / HTTP/1.1\r\n"";
$in .= ""Host: www.example.com\r\n"";
$in .= ""Connection: Close\r\n\r\n"";
$out = '';
echo 'Sending HTTP HEAD request...';
socket_write($socket, $in, strlen($in));
echo "OK.\n";
echo 'Reading response:\n\n';
while ($out = socket_read($socket, 2048)) {
echo $out;
}
echo 'Closing socket...';
socket_close($socket);
echo 'OK.\n\n';
?>
See also Sockets.
1.2.471.1. Specs¶
Short name |
Extensions/Extsockets |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.472. ext/sphinx¶
Extension for the Sphinx search server.
This extension provides bindings for Sphinx search client library.
<?php
$s = new SphinxClient;
$s->setServer(localhost, 6712);
$s->setMatchMode(SPH_MATCH_ANY);
$s->setMaxQueryTime(3);
$result = $s->query(test);
var_dump($result);
?>
See also Sphinx Client and Sphinx Search.
1.2.472.1. Specs¶
Short name |
Extensions/Extsphinx |
Rulesets |
|
Exakat since |
0.11.3 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.473. ext/spl¶
SPL extension.
The Standard PHP Library (SPL) is a collection of interfaces and classes that are meant to solve common problems.
<?php
// Example with FilesystemIterator
$files = new FilesystemIterator('/path/to/dir');
foreach($files as $file) {
echo $file->getFilename() . PHP_EOL;
}
?>
See also Standard PHP Library (SPL).
1.2.473.1. Specs¶
Short name |
Extensions/Extspl |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.474. ext/sqlite¶
Extension Sqlite 2.
Support for SQLite version 2 databases. The support for this version of Sqlite is not maintained anymore. It is recommended to use SQLite3.
<?php
if ($db = sqlite_open('mysqlitedb', 0666, $sqliteerror)) {
sqlite_query($db, 'CREATE TABLE foo (bar varchar(10))');
sqlite_query($db, 'INSERT INTO foo VALUES ("fnord")');
$result = sqlite_query($db, 'select bar from foo');
var_dump(sqlite_fetch_array($result));
} else {
die($sqliteerror);
}
?>
See also ext/sqlite and SQLite.
1.2.474.1. Specs¶
Short name |
Extensions/Extsqlite |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.475. ext/sqlite3¶
Extension Sqlite3.
Support for SQLite version 3 databases.
<?php
$db = new SQLite3('mysqlitedb.db');
$results = $db->query('SELECT bar FROM foo');
while ($row = $results->fetchArray()) {
var_dump($row);
}
?>
See also ext/sqlite3 and Sqlite.
1.2.475.1. Specs¶
Short name |
Extensions/Extsqlite3 |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.476. ext/sqlsrv¶
Extension for Microsoft SQL Server Driver.
The SQLSRV extension allows you to access Microsoft SQL Server and SQL Azure databases when running PHP on Windows.
<?php
$serverName = 'serverName\sqlexpress';
$connectionInfo = array( 'Database'=>'dbName', 'UID'=>'username', 'PWD'=>'password' );
$conn = sqlsrv_connect( $serverName, $connectionInfo);
if( $conn === false ) {
die( print_r( sqlsrv_errors(), true));
}
$sql = 'INSERT INTO Table_1 (id, data) VALUES (?, ?)';
$params = array(1, 'some data');
$stmt = sqlsrv_query( $conn, $sql, $params);
if( $stmt === false ) {
die( print_r( sqlsrv_errors(), true));
}
?>
See also Microsoft SQL Server Driver and PHP Driver for SQL Server Support for LocalDB.
1.2.476.1. Specs¶
Short name |
Extensions/Extsqlsrv |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.477. ext/ssh2¶
Extension ext/ssh2.
<?php
/* Notify the user if the server terminates the connection */
function my_ssh_disconnect($reason, $message, $language) {
printf("Server disconnected with reason code [%d] and message: %s\n",
$reason, $message);
}
$methods = array(
'kex' => 'diffie-hellman-group1-sha1',
'client_to_server' => array(
'crypt' => '3des-cbc',
'comp' => 'none'),
'server_to_client' => array(
'crypt' => 'aes256-cbc,aes192-cbc,aes128-cbc',
'comp' => 'none'));
$callbacks = array('disconnect' => 'my_ssh_disconnect');
$connection = ssh2_connect('shell.example.com', 22, $methods, $callbacks);
if (!$connection) die('Connection failed');
?>
See also SSH2 functions and ext/ssh2 on PECL.
1.2.477.1. Specs¶
Short name |
Extensions/Extssh2 |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.478. ext/standard¶
Standards PHP functions.
This is not a real PHP extension : it covers the core functions.
<?php
/*
Our php.ini contains the following settings:
display_errors = On
register_globals = Off
post_max_size = 8M
*/
echo 'display_errors = ' . ini_get('display_errors') . PHP_EOL;
echo 'register_globals = ' . ini_get('register_globals') . PHP_EOL;
echo 'post_max_size = ' . ini_get('post_max_size') . PHP_EOL;
echo 'post_max_size+1 = ' . (ini_get('post_max_size')+1) . PHP_EOL;
echo 'post_max_size in bytes = ' . return_bytes(ini_get('post_max_size'));
function return_bytes($val) {
$val = trim($val);
$last = strtolower($val[strlen($val)-1]);
switch($last) {
// The 'G' modifier is available since PHP 5.1.0
case 'g':
$val *= 1024;
case 'm':
$val *= 1024;
case 'k':
$val *= 1024;
}
return $val;
}
?>
See also PHP Options/Info Functions.
1.2.478.1. Specs¶
Short name |
Extensions/Extstandard |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.479. ext/stats¶
Statistics extension.
This extension contains few dozens of functions useful for statistical computations. It is a wrapper around 2 scientific libraries, namely DCDFLIB (Library of C routines for Cumulative Distributions Functions, Inverses, and Other parameters) by B. Brown & J. Lavato and RANDLIB by Barry Brown, James Lavato & Kathy Russell.
<?php
$x = [ 15, 16, 8, 6, 15, 12, 12, 18, 12, 20, 12, 14, ];
$y = [ 17.24, 15, 14.91, 4.5, 18, 6.29, 19.23, 18.69, 7.21, 42.06, 7.5, 8,];
sprintf(%2.9f, stats_covariance($a_1, $a_2));
?>
See also Statistics and ext/stats.
1.2.479.1. Specs¶
Short name |
Extensions/Extstats |
Rulesets |
|
Exakat since |
0.11.5 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.480. String¶
Strings in PHP. Strings are part of the core of PHP, and are not a separate extension.
<?php
$str = Mary Had A Little Lamb and She LOVED It So;
$str = strtolower($str);
echo $str; // Prints mary had a little lamb and she loved it so
?>
See also String functions.
1.2.480.1. Specs¶
Short name |
Extensions/Extstring |
Rulesets |
|
Exakat since |
0.9.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.481. ext/suhosin¶
Suhosin extension.
Suhosin (pronounced ‘su-ho-shin’) is an advanced protection system for PHP installations. It was designed to protect servers and users from known and unknown flaws in PHP applications and the PHP core.
<?php
// sha256 is a ext/suhosin specific function
$sha256 = sha256($string);
?>
See also Suhosin.org
1.2.481.1. Specs¶
Short name |
Extensions/Extsuhosin |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.482. ext/svm¶
Extension
SVM.
SVM is in interface with the libsvm, from . ``libsvm``is a library for Support Vector Machines, a classification tool for machine learning.
<?php
$data = array(
array(-1, 1 => 0.43, 3 => 0.12, 9284 => 0.2),
array(1, 1 => 0.22, 5 => 0.01, 94 => 0.11),
);
$svm = new SVM();
$model = $svm->train($data);
$data = array(1 => 0.43, 3 => 0.12, 9284 => 0.2);
$result = $model->predict($data);
var_dump($result);
$model->save('model.svm');
?>
See also SVM, LIBSVM – A Library for Support Vector Machines, ext/svm and ianbarber/php-svm.
1.2.482.1. Specs¶
Short name |
Extensions/Extsvm |
Rulesets |
|
Exakat since |
1.7.8 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.483. ext/swoole¶
Swoole : Production-Grade Async programming Framework for PHP.
Swoole is an event-driven asynchronous & concurrent networking communication framework with high performance written only in C for PHP.
<?php
for($i = 0; $i < 100; $i++) {
Swoole\Coroutine::create(function() use ($i) {
$redis = new Swoole\Coroutine\Redis();
$res = $redis->connect('127.0.0.1', 6379);
$ret = $redis->incr('coroutine');
$redis->close();
if ($i == 50) {
Swoole\Coroutine::create(function() use ($i) {
$redis = new Swoole\Coroutine\Redis();
$res = $redis->connect('127.0.0.1', 6379);
$ret = $redis->set('coroutine_i', 50);
$redis->close();
});
}
});
}
?>
See also Swoole and Swoole src.
1.2.483.1. Specs¶
Short name |
Extensions/Extswoole |
Rulesets |
|
Exakat since |
0.12.0 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.484. ext/tidy¶
Extension Tidy.
Tidy is a binding for the Tidy HTML clean and repair utility which allows you to not only clean and otherwise manipulate HTML documents, but also traverse the document tree.
<?php
ob_start();
?>
<html>a html document</html> .. code-block:: php
<?php $html = ob_get_clean();
// Specify configuration $config = array(
‘indent’ => true, ‘output-xhtml’ => true, ‘wrap’ => 200);
// Tidy $tidy = new tidy; $tidy->parseString($html, $config, ‘utf8’); $tidy->cleanRepair();
// Output echo $tidy; ?>
- See also Tidy <https://www.php.net/manual/en/book.`tidy.php>`_ and
HTML-`tidy <http://www.html-tidy.org/>`_.
1.2.484.1. Specs¶
Short name |
Extensions/Exttidy |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.485. ext/tokenizer¶
Extension Tokenizer.
The Tokenizer functions provide an interface to the PHP tokenizer embedded in the Zend Engine.
<?php
/*
* T_ML_COMMENT does not exist in PHP 5.
* The following three lines define it in order to
* preserve backwards compatibility.
*
* The next two lines define the PHP 5 only T_DOC_COMMENT,
* which we will mask as T_ML_COMMENT for PHP 4.
*/
if (!defined('T_ML_COMMENT')) {
define('T_ML_COMMENT', T_COMMENT);
} else {
define('T_DOC_COMMENT', T_ML_COMMENT);
}
$source = file_get_contents('example.php');
$tokens = token_get_all($source);
foreach ($tokens as $token) {
if (is_string($token)) {
// simple 1-character token
echo $token;
} else {
// token array
list($id, $text) = $token;
switch ($id) {
case T_COMMENT:
case T_ML_COMMENT: // we\'ve defined this
case T_DOC_COMMENT: // and this
// no action on comments
break;
default:
// anything else -> output 'as is'
echo $text;
break;
}
}
}
?>
See also tokenizer.
1.2.485.1. Specs¶
Short name |
Extensions/Exttokenizer |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.486. ext/tokyotyrant¶
Extension for Tokyo Tyrant.
tokyo_tyrant extension provides a wrapper for Tokyo Tyrant client libraries.
<?php
$tt = new TokyoTyrant("localhost");
$tt->put("key", "value");
echo $tt->get("key");
?>
See also tokyo_tyrant and Tokyo cabinet.
1.2.486.1. Specs¶
Short name |
Extensions/Exttokyotyrant |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.487. ext/trader¶
Extension trader.
The trader extension is a free open source stock library based on TA-Lib. It’s dedicated to trading software developers requiring to perform technical analysis of financial market data.
<?php
// get_data() reads the data from a source
var_dump(trader_avgprice(
get_data(open, $data0),
get_data(high, $data0),
get_data(low, $data0),
get_data(close, $data0)
));
?>
See also trader (PECL), ‘TA-lib <http://www.ta-lib.org/>`_ and ext/trader.
1.2.487.1. Specs¶
Short name |
Extensions/Exttrader |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.488. ext/uopz¶
Extension UOPZ : User Operations for Zend.
The uopz extension is focused on providing utilities to aid with unit testing PHP code.
It supports the following activities: Intercepting function execution, Intercepting object creation, Hooking into function execution, Manipulation of function statics, Manipulation of function flags, Redefinition of constants, Deletion of constants, Runtime creation of functions and methods,
<?php
// The example is extracted from the UOPZ extension test suite : tests/001.phpt
class Foo {
public function bar(int $arg) : int {
return $arg;
}
}
var_dump(uopz_set_return(Foo::class, 'bar', true));
$foo = new Foo();
var_dump($foo->bar(1));
uopz_set_return(Foo::class, 'bar', function(int $arg) : int {
return $arg * 2;
}, true);
var_dump($foo->bar(2));
try {
uopz_set_return(Foo::class, 'nope', 1);
} catch(Throwable $t) {
var_dump($t->getMessage());
}
class Bar extends Foo {}
try {
uopz_set_return(Bar::class, 'bar', null);
} catch (Throwable $t) {
var_dump($t->getMessage());
}
uopz_set_something(Bar::class, 'bar', null);
?>
See also ext/uopz and User Operations for Zend.
1.2.488.1. Specs¶
Short name |
Extensions/Extuopz |
Rulesets |
|
Exakat since |
1.1.7 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.489. ext/uuid¶
Extension
UUID. A universally unique identifier (UUID) is a 128-bit number used to identify information in computer systems.
An interface to the libuuid system library. The libuuid library is used to generate unique identifiers for objects that may be accessible beyond the local system. The Linux implementation was created to uniquely identify ext2 filesystems created by a machine. This library generates UUIDs compatible with those created by the Open Software Foundation (OSF) Distributed Computing Environment (DCE) utility uuidgen.
<?php
// example from the test suitee of the extension.
// check basic format of generated UUIDs
$uuid = uuid_create();
if (preg_match("/[[:xdigit:]]{8}-[[:xdigit:]]{4}-[[:xdigit:]]{4}-[[:xdigit:]]{4}-[[:xdigit:]]{12}/", $uuid)) {
echo "basic format ok\n";
} else {
echo "basic UUID format check failed, generated UUID was $uuid\n";
}
?>
- See also libuuid <https://linux.`die.net/man/3/libuuid>`_ and
1.2.489.1. Specs¶
Short name |
Extensions/Extuuid |
Rulesets |
|
Exakat since |
1.7.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.490. ext/v8js¶
Extension v8js.
This extension embeds the V8 Javascript Engine into PHP.
<?php
$v8 = new V8Js();
/* basic.js */
$JS = <<< EOT
len = print('Hello' + ' ' + 'World!' + '\n');
len;
EOT;
try {
var_dump($v8->executeString($JS, 'basic.js'));
} catch (V8JsException $e) {
var_dump($e);
}
?>
See also V8 Javascript Engine Integration, V8 Javascript Engine for PHP and pecl v8js.
1.2.490.1. Specs¶
Short name |
Extensions/Extv8js |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.491. ext/varnish¶
Extension PHP for varnish.
Varnish Cache is an open source, state of the art web application accelerator. The extension makes it possible to interact with a running varnish instance through TCP socket or shared memory.
<?php
$args = array(
VARNISH_CONFIG_HOST => '::1',
VARNISH_CONFIG_PORT => 6082,
VARNISH_CONFIG_SECRET => '5174826b-8595-4958-aa7a-0609632ad7ca',
VARNISH_CONFIG_TIMEOUT => 300,
);
$va = new VarnishAdmin($args);
?>
See also ext/varnish and pecl/Varnish.
1.2.491.1. Specs¶
Short name |
Extensions/Extvarnish |
Rulesets |
|
Exakat since |
1.1.7 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.492. ext/vips¶
Extension VIPS.
The VIPS image processing system is a very fast, multi-threaded image processing library with low memory needs.
<?php
dl('vips.' . PHP_SHLIB_SUFFIX);
$x = vips_image_new_from_file($argv[1])[out];
vips_image_write_to_file($x, $argv[2]);
?>
See also php-vips-ext, libvips and libvips adapter for PHP Imagine.
1.2.492.1. Specs¶
Short name |
Extensions/Extvips |
Rulesets |
|
Exakat since |
1.0.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.493. ext/wasm¶
Extension WASM.
The goal of the project is to be able to run WebAssembly binaries from PHP directly. So much fun coming!
From the php-ext-wasm documentation :
<?php
//There is a toy program in examples/simple.rs, written in Rust (or any other language that compiles to WASM):
// Stored in file __DIR__ . '/simple.wasm'
/*
#[no_mangle]
pub extern C fn sum(x: i32, y: i32) -> i32 {
x + y
}
*/
$instance = new WASM\Instance(__DIR__ . '/simple.wasm');
var_dump(
$instance->sum(5, 37) // 42!
);
?>
See also php-ext-wasm.
1.2.493.1. Specs¶
Short name |
Extensions/Extwasm |
Rulesets |
|
Exakat since |
1.5.7 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.494. ext/wddx¶
Extension WDDX.
The Web Distributed Data Exchange, or WDDX, is a free, open XML-based technology that allows Web applications created with any platform to easily exchange data with one another over the Web.
<?php
echo wddx_serialize_value("PHP to WDDX packet example", "PHP packet");
?>
See also Wddx on PHP and WDDX.
1.2.494.1. Specs¶
Short name |
Extensions/Extwddx |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.495. ext/weakref¶
Weak References for PHP.
Weak references provide a non-intrusive gateway to ephemeral objects. Unlike normal (strong) references, weak references do not prevent the garbage collector from freeing that object. For this reason, an object may be destroyed even though a weak reference to that object still exists. In such conditions, the weak reference seamlessly becomes invalid.
<?php
class MyClass {
public function __destruct() {
echo Destroying object!\n;
}
}
$o1 = new MyClass;
$r1 = new WeakRef($o1);
if ($r1->valid()) {
echo Object still exists!\n;
var_dump($r1->get());
} else {
echo Object is dead!\n;
}
unset($o1);
if ($r1->valid()) {
echo Object still exists!\n;
var_dump($r1->get());
} else {
echo Object is dead!\n;
}
?>
See also Weak references and PECL extension that implements weak references and weak maps in PHP.
1.2.495.1. Specs¶
Short name |
Extensions/Extweakref |
Rulesets |
|
Exakat since |
1.6.5 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.496. ext/wikidiff2¶
Extension wikidiff2.
Wikidiff2 is a PHP and HHVM module that provides the external diff engine for MediaWiki.
<?php
$x = <<<EOT
foo bar
baz
quux
bang
EOT;
$y = <<<EOT
foo test
baz
test
bang
EOT;
print wikidiff2_inline_diff( $x, $y, 2 );
?>
See also wikidiff2 and wikidiff2 (C ext).
1.2.496.1. Specs¶
Short name |
Extensions/Extwikidiff2 |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.497. ext/wincache¶
Extension Wincache.
The Wincache extension for PHP is a PHP accelerator that is used to increase the speed of PHP applications running on Windows and Windows Server.
<?php
$fp = fopen('/tmp/lock.txt', 'r+');
if (wincache_lock(“lock_txt_lock”)) { // do an exclusive lock
ftruncate($fp, 0); // truncate file
fwrite($fp, 'Write something here\n');
wincache_unlock(“lock_txt_lock”); // release the lock
} else {
echo 'Couldn't get the lock!';
}
fclose($fp);
?>
See also WinCache Homepage.
1.2.497.1. Specs¶
Short name |
Extensions/Extwincache |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.498. ext/xattr¶
Extensions xattr.
The xattr extension allows for the manipulation of extended attributes on a filesystem.
<?php
$file = 'my_favourite_song.wav';
xattr_set($file, 'Artist', 'Someone');
xattr_set($file, 'My ranking', 'Good');
xattr_set($file, 'Listen count', '34');
/* ... other code ... */
printf('You\'ve played this song %d times', xattr_get($file, 'Listen count'));
?>
See also xattr and Extended attributres.
1.2.498.1. Specs¶
Short name |
Extensions/Extxattr |
Rulesets |
|
Exakat since |
0.12.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.499. ext/xcache¶
Extension Xcache.
XCache is a open-source opcode cacher, which means that it accelerates the performance of PHP on servers.
<?php
if (!xcache_isset(count)) {
xcache_set(count, load_count_from_mysql());
}
?>
This guest book has been visited .. code-block:: php
<?php echo $count = xcache_inc(count); ?>
times.
<?php
// save every 100 hits
if (($count % 100) == 0) {
save_count_to_mysql($count);
}
?>
See also xcache.
1.2.499.1. Specs¶
Short name |
Extensions/Extxcache |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.500. ext/xdebug¶
Xdebug extension.
The Xdebug is a extension PHP which provides debugging and profiling capabilities.
<?php
class Strings
{
static function fix_string($a)
{
echo
xdebug_call_class().
"::".
xdebug_call_function().
" is called at ".
xdebug_call_file().
":".
xdebug_call_line();
}
}
$ret = Strings::fix_string( 'Derick' );
?>
See also Xdebug.
1.2.500.1. Specs¶
Short name |
Extensions/Extxdebug |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.501. ext/xdiff¶
Extension xdiff.
xdiff extension enables you to create and apply patch files containing differences between different revisions of files.
<?php
$old_version = 'my_script-1.0.php';
$patch = 'my_script.patch';
$errors = xdiff_file_patch($old_version, $patch, 'my_script-1.1.php');
if (is_string($errors)) {
echo 'Rejects:'.PHP_EOL;
echo $errors;
}
?>
1.2.501.1. Specs¶
Short name |
Extensions/Extxdiff |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.502. ext/xhprof¶
Extension xhprof.
XHProf is a light-weight hierarchical and instrumentation based profiler.
<?php
xhprof_enable(XHPROF_FLAGS_CPU + XHPROF_FLAGS_MEMORY);
for ($i = 0; $i <= 1000; $i++) {
$a = $i * $i;
}
$xhprof_data = xhprof_disable();
$XHPROF_ROOT = '/tools/xhprof/';
include_once $XHPROF_ROOT . '/xhprof_lib/utils/xhprof_lib.php';
include_once $XHPROF_ROOT . '/xhprof_lib/utils/xhprof_runs.php';
$xhprof_runs = new XHProfRuns_Default();
$run_id = $xhprof_runs->save_run($xhprof_data, 'xhprof_testing');
echo 'http://localhost/xhprof/xhprof_html/index.php?run={$run_id}&source=xhprof_testing'.PHP_EOL;
?>
See also XHprof Documentation.
1.2.502.1. Specs¶
Short name |
Extensions/Extxhprof |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.503. ext/xml¶
Extension xml (Parser).
This PHP extension implements support for James Clark’s expat in PHP. This toolkit lets you parse, but not validate, XML documents.
<?php
$file = data.xml;
$depth = array();
function startElement($parser, $name, $attrs)
{
global $depth;
if (!isset($depth[$parser])) {
$depth[$parser] = 0;
}
for ($i = 0; $i < $depth[$parser]; $i++) {
echo ;
}
echo $name\n;
$depth[$parser]++;
}
function endElement($parser, $name)
{
global $depth;
$depth[$parser]--;
}
$xml_parser = xml_parser_create();
xml_set_element_handler($xml_parser, startElement, endElement);
if (!($fp = fopen($file, r))) {
die(could not open XML input);
}
while ($data = fread($fp, 4096)) {
if (!xml_parse($xml_parser, $data, feof($fp))) {
die(sprintf(XML error: %s at line %d,
xml_error_string(xml_get_error_code($xml_parser)),
xml_get_current_line_number($xml_parser)));
}
}
xml_parser_free($xml_parser);
?>
See also XML Parser.
1.2.503.1. Specs¶
Short name |
Extensions/Extxml |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.504. ext/xmlreader¶
Extension XMLReader.
The XMLReader extension is an XML Pull parser. The reader acts as a cursor going forward on the document stream and stopping at each node on the way.
<?php
$xmlreader = new XMLReader();
$xmlreader->xml("<xml><div>Content</div></xml>");
$xmlreader->read();
$xmlreader->read();
$xmlreader->readString();
?>
See also xmlreader.
1.2.504.1. Specs¶
Short name |
Extensions/Extxmlreader |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.505. ext/xmlrpc¶
Extension ext/xmlrpc.
This extension can be used to write XML-RPC servers and clients.
<?php
$request = xmlrpc_encode_request('method', array(1, 2, 3));
$context = stream_context_create(array('http' => array(
'method' => 'POST',
'header' => 'Content-Type: text/xml',
'content' => $request
)));
$file = file_get_contents('http://www.example.com/xmlrpc', false, $context);
$response = xmlrpc_decode($file);
if ($response && xmlrpc_is_fault($response)) {
trigger_error('xmlrpc: '.$response['faultString'].' ('.$response['faultCode']));
} else {
print_r($response);
}
?>
See also XML-RPC.
1.2.505.1. Specs¶
Short name |
Extensions/Extxmlrpc |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.506. ext/xmlwriter¶
Extension ext/xmlwriter.
The XMLWriter extension wraps the libxml xmlWriter API inside PHP.
<?php
$xw = xmlwriter_open_memory();
xmlwriter_set_indent($xw, TRUE);
xmlwriter_start_document($xw, NULL, 'UTF-8');
xmlwriter_start_element($xw, 'root');
xmlwriter_write_attribute_ns($xw, 'prefix', '', 'http://www.php.net/uri');
xmlwriter_start_element($xw, 'elem1');
xmlwriter_write_attribute($xw, 'attr1', 'first');
xmlwriter_end_element($xw);
xmlwriter_full_end_element($xw);
xmlwriter_end_document($xw);
$output = xmlwriter_flush($xw, true);
print $output;
// write attribute_ns without start_element first
$xw = xmlwriter_open_memory();
var_dump(xmlwriter_write_attribute_ns($xw, 'prefix', 'id', 'http://www.php.net/uri', 'elem1'));
print xmlwriter_output_memory($xw);
?>
See also XMLWriter and Module xmlwriter from libxml2.
1.2.506.1. Specs¶
Short name |
Extensions/Extxmlwriter |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.507. ext/xsl¶
Extension XSL.
The XSL extension implements the XSL standard, performing XSLT transformations using the libxslt library.
<?php
// Example from the PHP manual
$xmldoc = new DOMDocument();
$xsldoc = new DOMDocument();
$xsl = new XSLTProcessor();
$xmldoc->loadXML('fruits.xml');
$xsldoc->loadXML('fruits.xsl');
libxml_use_internal_errors(true);
$result = $xsl->importStyleSheet($xsldoc);
if (!$result) {
foreach (libxml_get_errors() as $error) {
echo "Libxml error: {$error->message}\n";
}
}
libxml_use_internal_errors(false);
if ($result) {
echo $xsl->transformToXML($xmldoc);
}
?>
See also XSL extension;
1.2.507.1. Specs¶
Short name |
Extensions/Extxsl |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.508. ext/xxtea¶
Extension xxtea : XXTEA encryption algorithm extension for PHP.
XXTEA is a fast and secure encryption algorithm. This is a XXTEA extension for PHP. It is different from the original XXTEA encryption algorithm. It encrypts and decrypts string instead of uint32 array, and the key is also string.
<?php
// Example is extracted from the xxtea repository on github : tests/xxtea.phpt
$str = 'Hello World! 你好,中国🇨🇳!';
$key = '1234567890';
$base64 = 'D4t0rVXUDl3bnWdERhqJmFIanfn/6zAxAY9jD6n9MSMQNoD8TOS4rHHcGuE=';
$encrypt_data = xxtea_encrypt($str, $key);
$decrypt_data = xxtea_decrypt($encrypt_data, $key);
if ($str == $decrypt_data && base64_encode($encrypt_data) == $base64) {
echo 'success!';
} else {
echo base64_encode($encrypt_data);
echo 'fail!';
}
?>
See also PECL ext/xxtea and ext/xxtea on Github.
1.2.508.1. Specs¶
Short name |
Extensions/Extxxtea |
Rulesets |
|
Exakat since |
1.1.7 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.509. ext/yaml¶
Extension YAML.
This extension implements the YAML Ain’t Markup Language (YAML) data serialization standard. Parsing and emitting are handled by the LibYAML library.
<?php
$addr = array(
'given' => 'Chris',
'family'=> 'Dumars',
'address'=> array(
'lines'=> '458 Walkman Dr.
Suite #292',
'city'=> 'Royal Oak',
'state'=> 'MI',
'postal'=> 48046,
),
);
$invoice = array (
'invoice'=> 34843,
'date'=> '2001-01-23',
'bill-to'=> $addr,
'ship-to'=> $addr,
'product'=> array(
array(
'sku'=> 'BL394D',
'quantity'=> 4,
'description'=> 'Basketball',
'price'=> 450,
),
array(
'sku'=> 'BL4438H',
'quantity'=> 1,
'description'=> 'Super Hoop',
'price'=> 2392,
),
),
'tax'=> 251.42,
'total'=> 4443.52,
'comments'=> 'Late afternoon is best. Backup contact is Nancy Billsmer @ 338-4338.',
);
// generate a YAML representation of the invoice
$yaml = yaml_emit($invoice);
var_dump($yaml);
// convert the YAML back into a PHP variable
$parsed = yaml_parse($yaml);
// check that roundtrip conversion produced an equivalent structure
var_dump($parsed == $invoice);
?>
See also YAML.
1.2.509.1. Specs¶
Short name |
Extensions/Extyaml |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.510. ext/yis¶
Yellow Pages extensions (NIS).
NIS (formerly called Yellow Pages) allows network management of important administrative files (e.g. the password file).
<?php
$entry = yp_first($domain, 'passwd.byname');
$key = key($entry);
$value = $entry[$key];
echo 'First entry in this map has key ' . $key . ' and value ' . $value;
?>
See also The Linux NIS(YP)/NYS/NIS+ HOWTO and YP/NIS.
1.2.510.1. Specs¶
Short name |
Extensions/Extyis |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.511. ext/zbarcode¶
Extension Zbarcode.
PHP extension for reading barcodes.
<?php
/* Create new image object */
$image = new ZBarCodeImage('test.jpg');
/* Create a barcode scanner */
$scanner = new ZBarCodeScanner();
/* Scan the image */
$barcode = $scanner->scan($image);
/* Loop through possible barcodes */
if (!empty($barcode)) {
foreach ($barcode as $code) {
printf('Found type %s barcode with data %s\n', $code['type'], $code['data']);
}
}
?>
See also php-zbarcode.
1.2.511.1. Specs¶
Short name |
Extensions/Extzbarcode |
Rulesets |
|
Exakat since |
0.9.5 |
PHP Version |
7.0+ |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.512. ext/zend_monitor¶
Extension
zend_monitor.
See also Zend Monitor - PHP API.
1.2.512.1. Specs¶
Short name |
Extensions/Extzendmonitor |
Rulesets |
|
Exakat since |
1.7.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.513. ext/zip¶
Extension ext/zip.
This extension enables you to transparently read or write ZIP compressed archives and the files inside them.
<?php
$zip = new ZipArchive();
$filename = './test112.zip';
if ($zip->open($filename, ZipArchive::CREATE)!==TRUE) {
exit('cannot open <$filename>');
}
$zip->addFromString('testfilephp.txt' . time(), '#1 This is a test string added as testfilephp.txt.'.PHP_EOL);
$zip->addFromString('testfilephp2.txt' . time(), '#2 This is a test string added as testfilephp2.txt.'.PHP_EOL);
$zip->addFile($thisdir . '/too.php','/testfromfile.php');
echo 'numfiles: ' . $zip->numFiles . PHP_EOL;
echo 'status:' . $zip->status . PHP_EOL;
$zip->close();
?>
See also Zip.
1.2.513.1. Specs¶
Short name |
Extensions/Extzip |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
Very high |
Available in |
1.2.514. ext/zlib¶
Extension ext/zlib.
<?php
$filename = tempnam('/tmp', 'zlibtest') . '.gz';
echo "<html>\n<head></head>\n<body>\n<pre>\n";
$s = "Only a test, test, test, test, test, test, test, test!\n";
// open file for writing with maximum compression
$zp = gzopen($filename, 'w9');
// write string to file
gzwrite($zp, $s);
// close file
gzclose($zp);
?>
See also Zlib.
1.2.514.1. Specs¶
Short name |
Extensions/Extzlib |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.515. ext/0mq¶
Extension ext/zmq for
0mq.
ØMQ is a software library that lets you quickly design and implement a fast message-based application.
<?php
// Example from https://github.com/kuying/ZeroMQ/blob/d80dcc3dc1c14a343ca90bbd656b98fd55366548/zguide/examples/PHP/msgqueue.php
/*
* Simple message queuing broker
* Same as request-reply broker but using QUEUE device
* @author Ian Barber <ian(dot)barber(at)gmail(dot)com>
*/
$context = new ZMQContext();
// Socket facing clients
$frontend = $context->getSocket(ZMQ::SOCKET_ROUTER);
$frontend->bind(tcp://*:5559);
// Socket facing services
$backend = $context->getSocket(ZMQ::SOCKET_DEALER);
$backend->bind(tcp://*:5560);
// Start built-in device
new ZMQDevice($frontend, $backend);
?>
1.2.515.1. Specs¶
Short name |
Extensions/Extzmq |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.516. ext/zookeeper¶
Extension for Apache Zookeeper.
ZooKeeper is an Apache project that enables centralized service for maintaining configuration information, naming, providing distributed synchronization, and providing group services.
<?php
$zookeeper = new Zookeeper('locahost:2181');
$path = '/path/to/node';
$value = 'nodevalue';
$zookeeper->set($path, $value);
$r = $zookeeper->get($path);
if ($r)
echo $r;
else
echo 'ERR';
?>
- See also ext/zookeeper,
Install `Zookeeper PHP Extension <https://blog.programster.org/install-zookeeper-php-extension>`_ Zookeeper and .
1.2.516.1. Specs¶
Short name |
Extensions/Extzookeeper |
Rulesets |
|
Exakat since |
1.2.5 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.517. Definitions Only¶
File is definition only.
Definition-only files only include structure definitions : class, functions, traits, interfaces, constants, global, declare(), use and include().
Some functioncalls are also considered definition only, as they configure PHP, but don’t process data : * ini_set() * error_reporting * register_shutdown_function() * set_session_handler() * set_error_handler() * spl_autoload_register()
File A : .. code-block:: php
<?php
// This file has only definitions function foo() {}
define(‘a’, 1);
class bar {}
?>
File B : .. code-block:: php
<?php
// This file has only definitions function foo() {}
define(‘a’, 1);
class bar {}
?>
1.2.517.1. Specs¶
Short name |
Files/DefinitionsOnly |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.518. Global Code Only¶
This file has only global code.
1.2.518.1. Specs¶
Short name |
Files/GlobalCodeOnly |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.519. Inclusion Wrong Case¶
Inclusion should follow exactly the case of included files and path. This prevents the infamous case-sensitive filesystem bug, where files are correctly included in a case-insensitive system, and failed to be when moved to production.
<?php
// There must exist a path called path/to and a file library.php with this case
include path/to/library.php;
// Error on the case, while the file does exist
include path/to/LIBRARY.php;
// Error on the case, on the PATH
include path/TO/library.php;
?>
See also include_once, about case sensitivity and inclusions.
1.2.519.1. Suggestions¶
Make the inclusion string identical to the file name.
Change the name of the file to reflect the actual inclusion. This is the best way when a naming convention has been set up for the project, and the file doesn’t adhere to it. Remember to change all other inclusion.
1.2.519.2. Specs¶
Short name |
Files/InclusionWrongCase |
Rulesets |
|
Exakat since |
1.1.1 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.520. Is CLI Script¶
Mark a file as a CLI script, based on the usage of #!.
1.2.520.1. Specs¶
Short name |
Files/IsCliScript |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.521. File Is Component¶
Check that a file only contains definition elements, such as traits, interfaces, classes, constants, global variables, use or inclusions.
Such a file is a component, that may be included in some other code and used. By itself, it doesn’t run.
1.2.521.1. Specs¶
Short name |
Files/IsComponent |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.522. Missing Include¶
The included files doesn’t exists in the repository. The inclusions target a files that doesn’t exist.
The analysis works with every type of inclusion : include(), require(), include_once() and require_once(). It also works with parenthesis when used as parameter delimiter.
The analysis doesn’t take into account include_path. This may yield false positives.
<?php
include 'non_existent.php';
// variables are not resolved. This won't be reported.
require ($path.'non_existent.php');
?>
Missing included files may lead to a fatal error, a warning or other error later in the execution.
Name |
Default |
Type |
Description |
constant_or_variable_name |
100 |
string |
Literal value to be used when including files. For example, by configuring ‘Files_MissingInclude[“HOME_DIR”] = “/tmp/myDir/”;’, then ‘include HOME_DIR . “my_class.php”; will be actually be used as ‘/tmp/myDir/my_class.php’. Constants must be configured with their correct case. Variable must be configured with their initial ‘$’. Configure any number of variable and constant names. |
1.2.522.1. Specs¶
Short name |
Files/MissingInclude |
Rulesets |
|
Exakat since |
1.1.2 |
PHP Version |
All |
Severity |
Critical |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.523. Not Definitions Only¶
Files should only include definitions (class, functions, traits, interfaces, constants), or global instructions, but not both.
<?php
// This whole script is a file
// It contains definitions and global code
class foo {
static public $foo = null;
}
//This can be a singleton creation
foo::$foo = new foo();
trait t {}
class bar {}
?>
Within this context, globals, use, and namespaces instructions are not considered a warning.
1.2.523.1. Specs¶
Short name |
Files/NotDefinitionsOnly |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.524. External Config Files¶
List services being used in this code repository, based on configuration files that are committed.
For example, a .git folder is an artefact of a GIT repository.
1.2.524.1. Specs¶
Short name |
Files/Services |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.525. Add Default Value¶
Parameter in methods definition may receive a default value. This allows the called method to set a value when the parameter is omitted.
<?php
function foo($i) {
if (!is_integer($i)) {
$i = 0;
}
}
?>
See also Function arguments.
1.2.525.1. Suggestions¶
Add a default value for parameters
1.2.525.2. Specs¶
Short name |
Functions/AddDefaultValue |
Rulesets |
|
Exakat since |
1.4.5 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.526. Aliases Usage¶
PHP manual recommends to avoid function aliases.
Some functions have several names, and both may be used the same way. However, one of the names is the main name, and the others are aliases. Aliases may be removed or change or dropped in the future. Even if this is not forecast, it is good practice to use the main name, instead of the aliases.
<?php
// official way to count an array
$n = count($array);
// official way to count an array
$n = sizeof($array);
?>
Aliases are compiled in PHP, and do not provide any performances over the normal function.
Aliases are more likely to be removed later, but they have been around for a long time.
See documentation : List of function aliases.
1.2.526.1. Suggestions¶
Always use PHP recommended functions
1.2.526.2. Specs¶
Short name |
Functions/AliasesUsage |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
ClearPHP |
|
Examples |
|
Available in |
1.2.527. Use Named Boolean In Argument Definition¶
Boolean in argument definitions is confusing.
It is recommended to use explicit constant names, instead. They are more readable. They also allow for easy replacement when the code evolve and has to replace those booleans by strings. This works even also with classes, and class constants.
<?php
function flipImage($im, $horizontal = NO_HORIZONTAL_FLIP, $vertical = NO_VERTICAL_FLIP) { }
// with constants
const HORIZONTAL_FLIP = true;
const NO_HORIZONTAL_FLIP = true;
const VERTICAL_FLIP = true;
const NO_VERTICAL_FLIP = true;
rotateImage($im, HORIZONTAL_FLIP, NO_VERTICAL_FLIP);
// without constants
function flipImage($im, $horizontal = false, $vertical = false) { }
rotateImage($im, true, false);
?>
See also Flag Argument, to avoid boolean altogether.
1.2.527.1. Specs¶
Short name |
Functions/AvoidBooleanArgument |
Rulesets |
|
Exakat since |
1.0.6 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Examples |
|
Available in |
1.2.528. Bad Typehint Relay¶
A bad typehint relay happens where a type hinted argument is relayed to a parameter with another typehint. This will lead to a Fatal error, and stop the code. This is possibly a piece of dead code.
<?php
// the $i argument is relayed to bar, which is expecting a string.
function foo(int $i) : string {
return bar($i);
}
// the return value for the bar function is not compatible with the one from foo;
function bar(string $s) : int {
return (int) $string + 1;
}
?>
It is recommended to harmonize the typehints, so the two methods are compatible.
1.2.528.1. Suggestions¶
Harmonize the typehint so they match one with the other.
Remove dead code
Apply type casting before calling the next function, or return value
1.2.528.2. Specs¶
Short name |
Functions/BadTypehintRelay |
Rulesets |
|
Exakat since |
1.6.6 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.529. Callback Function Needs Return¶
When used with array_map() functions, the callback must return something. This return may be in the form of a
returnstatement, a global variable or a parameter with a reference. All those solutions extract information from the callback.
<?php
// This filters each element
$filtered = array_filter($array, function ($x) {return $x == 2; });
// This return void for every element
$filtered = array_filter($array, function ($x) {return ; });
// costly array_sum()
$sum = 0;
$filtered = array_filter($array, function ($x) use (&$sum) {$sum += $x; });
// costly array_sum()
global $sum = 0;
$filtered = array_filter($array, function () {global $sum; $sum += $x; });
// register_shutown_function() doesn't require any return
register_shutown_function(my_shutdown);
?>
The following functions are omitted, as they don’t require the return :
1.2.529.1. Suggestions¶
Add an explicit return to the callback
Use null to unset elements in an array without destroying the index
See also and array_map.
1.2.529.2. Specs¶
Short name |
Functions/CallbackNeedsReturn |
Rulesets |
|
Exakat since |
1.2.6 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.530. Cancelled Parameter¶
When a parameter is hardcoded, and cannot be changed from the calling expression. The argument is in the signature, but it is later hardcoded to a literal value : thus, it is not usable, from the caller point of view.
Reference argument are omitted here, as the value change, however hardcoded, may have an impact on the calling code.
<?php
function foo($a, $b) {
// $b is cancelled, and cannot be changed.
$b = 3;
// $a is the only parameter here
return $a + $b;
}
function bar($a, $b) {
// $b is actually processed
$c = $b;
$c = process($c);
$b = $c;
// $a is the only parameter here
return $a + $b;
}
?>
1.2.530.1. Suggestions¶
Remove the parameter in the method signature
1.2.530.2. Specs¶
Short name |
Functions/CancelledParameter |
Rulesets |
|
Exakat since |
2.2.0 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.531. Cannot Use Static For Closure¶
The reported closures and arrow functions cannot use the static keyword.
Closures that makes use of the $this pseudo-variable cannot use the static keyword, at it prevents the import of the $this context in the closure. It will fail at execution.
Closures that makes use of the bindTo() method, to change the context of execution, also cannot use the static keyword. Even if $this is not used in the closure, the static keyword prevents the call to bindTo().
<?php
class x {
function foo() {
// Not possible, $this is now undefined in the body of the closure
static function () { return $this->a;};
}
function foo2() {
// Not possible, $this is now undefined in the body of the arrow function
static fn () => $this->a;
}
function foo3() {
// Not possible, the closure gets a new context before being called.
$a = static fn () => $ba;
$this->foo4($a);
}
function foo4($c) {
$c->bindTo($this);
$c();
}
}
?>
1.2.531.1. Suggestions¶
Remove the static keyword
Remove the call to bindTo() method
Remove the usage of the $this variable
1.2.531.2. Specs¶
Short name |
Functions/CannotUseStaticForClosure |
Rulesets |
|
Exakat since |
2.2.2 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
Medium |
Available in |
1.2.532. Cant Use Function¶
Those functions only contains an error or an exception. As such, they are a warning that such function or method shouldn’t be used.
<?php
function obsoleteFoo() {
throw new exception('Don\'t use obsoleteFoo() but rather the new version of foo().');
}
?>
1.2.532.1. Specs¶
Short name |
Functions/CantUse |
Rulesets |
|
Exakat since |
1.8.7 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.533. Closure Could Be A Callback¶
Closure or arrowfunction could be simplified to a callback. Callbacks are strings or arrays.
A simple closure that only returns arguments relayed to another function or method, could be reduced to a simpler expression. They
Closure may be simplified with a string, for functioncall, with an array for methodcalls and static methodcalls.
Performances : simplifying a closure tends to reduce the call time by 50%.
<?php
// Simple and faster call to strtoupper
$filtered = array_map('strtoupper', $array);
// Here the closure doesn't add any feature over strtoupper
$filtered = array_map(function ($x) { return strtoupper($x);}, $array);
// Methodcall example : no fix
$filtered = array_map(function ($x) { return $x->strtoupper() ;}, $array);
// Methodcall example : replace with array($y, 'strtoupper')
$filtered = array_map(function ($x) use ($y) { return $y->strtoupper($x) ;}, $array);
// Static methodcall example
$filtered = array_map(function ($x) { return $x::strtoupper() ;}, $array);
// Static methodcall example : replace with array('A', 'strtoupper')
$filtered = array_map(function ($x) { return A::strtoupper($x) ;}, $array);
?>
See also Closure class and Callbacks / Callables.
1.2.533.1. Suggestions¶
Replace the closure by a string, with the name of the called function
Replace the closure by an array, with the name of the called method and the object as first element
1.2.533.2. Specs¶
Short name |
Functions/Closure2String |
Rulesets |
|
Exakat since |
1.4.3 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.534. Closures Glossary¶
List of all the closures in the code.
<?php
// A closure is also a unnamed function
$closure = function ($arg) { return 'A'.strtolower($arg); }
?>
See also The `Closure Class <https://www.php.net/manual/en/class.closure.php>`_.
1.2.534.1. Specs¶
Short name |
Functions/Closures |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
Very high |
Available in |
1.2.535. Conditioned Function¶
Indicates if a function is defined only if a condition is met.
<?php
// This is a conditioned function. // it only exists if the PHP binary doesn’t have it already. if (!function_exists(‘join’)) {
- function join($glue, $array) {
return implode($glue, $array);
}
}
1.2.535.1. Specs¶
Short name |
Functions/ConditionedFunctions |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.536. Could Be Typehinted Callable¶
Those arguments may use the callable Typehint.
‘callable’ is a PHP keyword that represents callback functions. Those may be used in dynamic function call, like $function(); or as callback functions, like with array_map();
callable may be a string representing a function name or a static call (including ::), an array with two elements, (a class or object, and a method), or a closure.
When arguments are used to call a function, but are not marked with ‘callable’, they are reported by this analysis.
<?php
function foo(callable $callable) {
// very simple callback
return $callable();
}
function foo2($array, $callable) {
// very simple callback
return array_map($array, $callable);
}
?>
See also Callback / callable.
1.2.536.1. Suggestions¶
Add the typehint callable
Use the function is_callable() inside the method if ‘callable’ is too strong.
1.2.536.2. Specs¶
Short name |
Functions/CouldBeCallable |
Rulesets |
|
Exakat since |
0.10.5 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.537. Could Be Static Closure¶
By preventing the useless import of $this, you avoid useless work.
This also has the added value to prevent the usage of $this from the closure. This is a good security practice.
<?php
class Foo
{
function __construct()
{
// Not possible to use $this
$func = static function() {
var_dump($this);
};
$func();
// Normal import of $this
$closure = function() {
var_dump($this);
};
}
};
new Foo();
?>
This is a micro-optimisation. Apply it in case of intensive usage.
See also Anonymous functions, GeneratedHydrator and Static anonymous functions <https://www.php.net/manual/en/functions.anonymous.php#functions.anonymous-functions.`static>`_.
1.2.537.1. Suggestions¶
Add the static keyword to the closure.
Make actual usage of $this in the closure.
1.2.537.2. Specs¶
Short name |
Functions/CouldBeStaticClosure |
Rulesets |
|
Exakat since |
1.3.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.538. Could Make A Function¶
When a function is called across the code with the same arguments often enough, it should be turned into a local API.
This approach is similar to turning literals into constants : it centralize the value, it helps refactoring by updating it. It also makes the code more readable. Moreover, it often highlight common grounds between remote code locations.
The analysis looks for functions calls, and checks the arguments. When the calls occurs more than 4 times, it is reported.
<?php
// str_replace is used to clean '&' from strings.
// It should be upgraded to a central function
function foo($arg ) {
$arg = str_replace('&', '', $arg);
// do something with $arg
}
class y {
function bar($database ) {
$value = $database->queryName();
$value = str_replace('&', '', $value);
// $value = removeAmpersand($value);
// do something with $arg2
}
}
// helper function
function removeAmpersand($string) {
return str_replace('&', '', $string);
}
?>
See also Don’t repeat yourself (DRY).
1.2.538.1. Suggestions¶
Create a constant for common pieces of data
Create a function based on context-free repeated elements
Create a class based on repeated elements with dependent values
Name |
Default |
Type |
Description |
centralizeThreshold |
8 |
integer |
Minimal number of calls of the function with one common argument. |
1.2.538.2. Specs¶
Short name |
Functions/CouldCentralize |
Rulesets |
|
Exakat since |
0.11.6 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.539. Could Type With Array¶
That argument may be typed with
array.
<?php
// $a is used with a function which requires an int.
function foo($a) {
return array_keys($a);
}
?>
See also Type declarations.
1.2.539.1. Suggestions¶
Add the
arraytypehint to the function.
1.2.539.2. Specs¶
Short name |
Functions/CouldTypeWithArray |
Rulesets |
|
Exakat since |
1.9.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.540. Could Type With Boolean¶
That argument may be typed with
bool.
<?php
// $a is used with a function which requires a boolean.
function foo($code, $a) {
return var_dump($code, $a);
}
?>
See also Type declarations.
1.2.540.1. Suggestions¶
Add the
booltypehint to the function.
1.2.540.2. Specs¶
Short name |
Functions/CouldTypeWithBool |
Rulesets |
|
Exakat since |
1.9.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.541. Could Type With Int¶
That argument may be typed with
int.
<?php
// $a is used with a function which requires an int.
function foo($a) {
return chr($a);
}
?>
See also Type declarations.
1.2.541.1. Suggestions¶
Add the
inttypehint to the function.
1.2.541.2. Specs¶
Short name |
Functions/CouldTypeWithInt |
Rulesets |
|
Exakat since |
1.9.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.542. Could Type With Iterable¶
Suggest using
iterabletypehint for arguments.
iterable represents both array and objects that implements Iterator interface. Both types are coerced, and usable here.
<?php
// $s may be both an array or an iterator
function foo($s) : int {
$t = 0;
foreach($s as $v) {
$t += (int) $v;
}
return $t;
}
?>
See also Iterables.
1.2.542.1. Suggestions¶
Add the iterable type
1.2.542.2. Specs¶
Short name |
Functions/CouldTypeWithIterable |
Rulesets |
|
Exakat since |
1.9.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Medium |
Available in |
1.2.543. Could Type With String¶
That argument may be typed with
string.
<?php
// $a is used with a function which requires a string.
function foo($a) {
return strtolower($a);
}
?>
See also Type declarations.
1.2.543.1. Suggestions¶
Add the
stringtypehint to the function.
1.2.543.2. Specs¶
Short name |
Functions/CouldTypeWithString |
Rulesets |
|
Exakat since |
1.9.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.544. Could Typehint¶
Arguments that are tested with instanceof gain from making it a Typehint.
<?php
function foo($a, $b) {
// $a is tested for B with instanceof.
if (!$a instanceof B) {
return;
}
// More code
}
function foo(B $a, $b) {
// May omit the initial test
// More code
}
?>
1.2.544.1. Suggestions¶
Add the typehint, remove the test on the type
1.2.544.2. Specs¶
Short name |
Functions/CouldTypehint |
Rulesets |
|
Exakat since |
0.11.5 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.545. Deep Definitions¶
Structures, such as functions, classes, interfaces, traits, etc. may be defined anywhere in the code, including inside functions. This is legit code for PHP.
Since the availability of autoload, with spl_register_autoload(), there is no need for that kind of code. Structures should be defined, and accessible to the autoloading. Inclusions and deep definitions should be avoided, as they compel code to load some definitions, while autoloading will only load them if needed.
<?php
class X {
function init() {
// myFunction is defined when and only if X::init() is called.
if (!function_exists('myFunction'){
function myFunction($a) {
return $a + 1;
}
})
}
}
?>
Functions are excluded from autoload, but shall be gathered in libraries, and not hidden inside other code.
Constants definitions are tolerated inside functions : they may be used for avoiding repeat, or noting the usage of such function.
Definitions inside a if/then statement, that include PHP version check are accepted here.
See also Autoloading Classes.
1.2.545.1. Suggestions¶
Move function definitions to the global space : outside structures, and method.
1.2.545.2. Specs¶
Short name |
Functions/DeepDefinitions |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Examples |
|
Available in |
1.2.546. Dont Collect Void¶
When a method returns void, there is no need to collect the result. The collected value will actually be
null.
<?php
function foo() : void {
// doSomething()
}
// This is useless
$result = foo();
// This is useless. It looks like this is a left over from code refactoring
echo foo();
?>
1.2.546.1. Suggestions¶
Move the call to the function to its own expression with a semi-colon.
Remove assignation of the result of such calls.
See also and .
1.2.546.2. Specs¶
Short name |
Functions/DontUseVoid |
Rulesets |
|
Exakat since |
2.0.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Available in |
1.2.547. Duplicate Named Parameter¶
Two parameters have the same name in a method call. This will yield a Fatal error.
<?php
// parameters are all distinct
foo(a:1, b:2);
// parameter a is double
foo(a:1, a:1);
?>
1.2.547.1. Suggestions¶
Review the parameters names and remove the duplicates
Review the parameters names and makes the names unique
1.2.547.2. Specs¶
Short name |
Functions/DuplicateNamedParameter |
Rulesets |
|
Exakat since |
2.2.3 |
PHP Version |
8.0+ |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Unknown |
Available in |
1.2.548. Function With Dynamic Code¶
Mark a method, function, closure, arrow function that includes dynamic code.
Dynamic code is based on usage of include() and co, extract() and eval().
<?php
// Function with dynamic code
function foo($x) {
include $x;
return $y;
}
// Static coe Function
function foo($x) {
return $y + $x;
}
?>
This is a support rule, to help omits some special cases in other rules.
1.2.548.1. Specs¶
Short name |
Functions/DynamicCode |
Rulesets |
|
Exakat since |
2.1.8 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.549. Dynamic Function Call¶
Mark a functioncall made with a variable name.
<?php
// function definition
function foo() {}
// function name is in a variable, as a string.
$var = 'foo';
// dynamic call of a function
$var();
call_user_func($var);
?>
1.2.549.1. Specs¶
Short name |
Functions/Dynamiccall |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.550. Empty Function¶
Function or method whose body is empty.
Such functions or methods are rarely useful. As a bare minimum, the function should return some useful value, even if constant.
A method is considered empty when it contains nothing, or contains expressions without impact.
<?php
// classic empty function
function emptyFunction() {}
class bar {
// classic empty method
function emptyMethod() {}
// classic empty function
function emptyMethodWithParent() {}
}
class barbar extends bar {
// NOT an empty method : it overwrites the parent method
function emptyMethodWithParent() {}
}
?>
Methods which overwrite another methods are omitted. Methods which are the concrete version of an abstract method are considered.
1.2.550.1. Suggestions¶
Fill the function with actual code
Remove any usage of the function, then remove the function
1.2.550.2. Specs¶
Short name |
Functions/EmptyFunction |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.551. Exceeding Typehint¶
The typehint is not fully used in the method. Some of the defined methods in the typehint are unused. A tighter typehint could be used, to avoid method pollution.
<?php
interface i {
function i1();
function i2();
}
interface j {
function j1();
function j2();
}
function foo(i $a, j $b) {
// the i typehint is totally used
$a->i1();
$a->i2();
// the i typehint is not totally used : j2() is not used.
$b->j1();
}
?>
Tight typehint prevents the argument from doing too much. They also require more maintenance : creation of dedicated interfaces, method management to keep all typehint tight.
See also Insufficient Typehint.
1.2.551.1. Suggestions¶
Keep the typehint tight, do not inject more than needed.
1.2.551.2. Specs¶
Short name |
Functions/ExceedingTypehint |
Rulesets |
|
Exakat since |
2.0.3 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.552. Fallback Function¶
A function that is called with its name alone, and whose definition is in the global scope.
<?php
namespace {
// global definition
function foo() {}
}
namespace Bar {
// local definition
function foo2() {}
foo(); // definition is in the global namespace
foo2(); // definition is in the Bar namespace
}
?>
See also Using namespaces: fallback to global function/constant.
1.2.552.1. Specs¶
Short name |
Functions/FallbackFunction |
Rulesets |
|
Exakat since |
1.1.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.553. Fn Argument Variable Confusion¶
Avoid using local variables as arrow function arguments.
When a local variable name is used as an argument’s name in an arrow function, the local variable from the original scope is not imported. They are now two distinct variables.
When the local variable is not listed as argument, it is then imported in the arrow function.
<?php
function foo() {
$locale = 1;
// Actually ignores the argument, and returns the local variable ``$locale``.
$fn2 = fn ($argument) => $locale;
// Seems similar to above, but returns the incoming argument
$fn2 = fn ($locale) => $locale;
}
?>
See also Arrow functions.
1.2.553.1. Suggestions¶
Change the name of the local variable
Change the name of the argument
1.2.553.2. Specs¶
Short name |
Functions/FnArgumentVariableConfusion |
Rulesets |
|
Exakat since |
2.1.0 |
PHP Version |
7.4+ |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.554. Function Called With Other Case Than Defined¶
Functions and methods are defined with a specific case. Often, this is done on purpose,
either to distinguish the method from others, such as PHP natives functions, or to follow a naming convention.
PHP functions are case insensitive, which leads to situations like :
<?php
function myUtility($arg) {
/* some code here */
}
myutility($var);
?>
It is recommended to use the same casing in the function call and the function definition.
1.2.554.1. Suggestions¶
Use the same case for the function and its call.
1.2.554.2. Specs¶
Short name |
Functions/FunctionCalledWithOtherCase |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.555. Functions Glossary¶
List of all the defined functions in the code.
<?php
// A function
function aFunction() {}
// Closures (not reported)
$closure = function ($arg) { }
// Methods
class foo {
function aMethod() {}
}
?>
1.2.555.1. Specs¶
Short name |
Functions/Functionnames |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.556. Functions Using Reference¶
Functions and methods using references in their signature.
<?php
function usingReferences( &$a) {}
class foo {
public function methodUsingReferences($b, &$c = 1) {}
}
?>
1.2.556.1. Specs¶
Short name |
Functions/FunctionsUsingReference |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.557. Generator Cannot Return¶
Generators could not use return and yield at the same time. In PHP 7.0, generator can now use both of them.
<?php
// This is not allowed until PHP 7.0
function foo() {
yield 1;
return 'b';
}
?>
1.2.557.1. Suggestions¶
Remove the return
1.2.557.2. Specs¶
Short name |
Functions/GeneratorCannotReturn |
Rulesets |
CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, All |
Exakat since |
1.8.7 |
PHP Version |
7.0+ |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.558. Hardcoded Passwords¶
Hardcoded passwords in the code.
Hardcoding passwords is a bad idea. Not only it make the code difficult to change, but it is an information leak. It is better to hide this kind of information out of the code.
<?php
$ftp_server = '300.1.2.3'; // yes, this doesn't exists, it's an example
$conn_id = ftp_connect($ftp_server);
// login with username and password
$login_result = ftp_login($conn_id, 'login', 'password');
?>
See also 10 GitHub Security Best Practices and Git How-To: Remove Your Password from a Repository.
1.2.558.1. Suggestions¶
Remove all passwords from the code. Also, check for history if you are using a VCS.
Name |
Default |
Type |
Description |
passwordsKeys |
password_keys.json |
data |
List of array index and property names that shall be checked for potential secret key storages. |
1.2.558.2. Specs¶
Short name |
Functions/HardcodedPasswords |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
ClearPHP |
|
Available in |
1.2.559. Method Has Fluent Interface¶
Mark a method when it only returns $this.
Fluent interfaces allows for chaining methods calls. This implies that $this is always returned, so that the next method call is done on the same object.
<?php
$object = new foo();
$object->this()
->is()
->a()
->fluent()
->interface();
class foo {
function this() {
// doSomething
return $this;
}
function is() {
// doSomethingElse
return $this;
}
/// Etc. for a(), fluent(), interface()...
}
?>
See also Fluent Interfaces in PHP and Fluent Interfaces are Evil.
1.2.559.1. Specs¶
Short name |
Functions/HasFluentInterface |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.560. Method Has No Fluent Interface¶
Mark a method as such when it contains at least one return that doesn’t return $this.
1.2.560.1. Specs¶
Short name |
Functions/HasNotFluentInterface |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.561. Insufficient Typehint¶
An argument is typehinted, but it actually calls methods that are not listed in the interface.
Classes may be implementing more methods than the one that are listed in the interface they also implements. This means that filtering objects with a typehint, but calling other methods will be solved at execution time : if the method is available, it will be used; if it is not, a fatal error is reported.
<?php
class x implements i {
function methodI() {}
function notInI() {}
}
interface i {
function methodI();
}
function foo(i $x) {
$x->methodI(); // this call is valid
$x->notInI(); // this call is not garanteed
}
?>
Inspired by discussion with Brandon Savage.
1.2.561.1. Suggestions¶
Extend the interface with the missing called methods
Change the body of the function to use only the methods that are available in the interface
Change the used objects so they don’t depend on extra methods
1.2.561.2. Specs¶
Short name |
Functions/InsufficientTypehint |
Rulesets |
|
Exakat since |
1.6.6 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.562. Is An Extension Function¶
This is an extension function.
<?php
// range is a native PHP function. It is always available
$array = range(0, 100);
// json_encode is an extension function : it requires that PHP was compile with ext/json
echo json_encode($array);
?>
Almost every PHP extension defines extra functions. Nowadays, they are prefixed, like mysqli_connect, ldap_close, or zlib_decode. Sometimes, they are even in a namespace. Refer to the extension itself to learn more about its functions usage.
1.2.562.1. Specs¶
Short name |
Functions/IsExtFunction |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.563. Is Generator¶
Mark as such functions or methods that are using yield and yield from.
<?php
function generator() {
yield from generator2();
return 3;
}
function generator2() {
yield 1;
yield 2;
}
?>
1.2.563.1. Specs¶
Short name |
Functions/IsGenerator |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.564. Functioncall Is Global¶
Marks functioncall when they are global and not located in another function, class or trait (namespaces are OK).
1.2.564.1. Specs¶
Short name |
Functions/IsGlobal |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.565. Exit-like Methods¶
Those methods terminate the execution.
They are detected when they do call exit() <https://www.php.net/`exit>`_ or die() <https://www.php.net/`die>`_. They may also be identified with the PHP 8.0 #[NoReturn] attribute, or the PHPDOC @noreturn (case insensitive).
If they are called, they will stop the application. They are a user-land equivalent of exit or die.
<?php
// This function anytime the code has finished its processing.
function finish() {
global $html;
echo $html;
die();
}
?>
See also PhpStorm 2020.3 EAP #4: Custom PHP 8 Attributes.
1.2.565.1. Specs¶
Short name |
Functions/KillsApp |
Rulesets |
Attributes, CE, All |
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
Medium |
Available in |
1.2.566. Functions In Loop Calls¶
The following functions call each-other in a loop fashion : A -> B -> A.
When those functions have no other interaction, the code is useless and should be dropped.
<?php
function foo1($a) {
if ($a < 1000) {
return foo2($a + 1);
}
return $a;
}
function foo2($a) {
if ($a < 1000) {
return foo1($a + 1);
}
return $a;
}
// if foo1 nor foo2 are called, then this is dead code.
// if foo1 or foo2 are called, this recursive call should be investigated.
?>
Loops of size 2, 3 and 4 function are supported by this analyzer.
1.2.566.1. Suggestions¶
Drop all the functions in the loop, as they are dead code
1.2.566.2. Specs¶
Short name |
Functions/LoopCalling |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.567. Mark Callable¶
Create an attribute that guess what are the called function or methods, when possible.
1.2.567.1. Specs¶
Short name |
Functions/MarkCallable |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.568. Mismatch Parameter And Type¶
When the name of the parameter contradicts the type of the parameter.
This is mostly semantics, so it will affect the coder and the auditor of the code. PHP is immune to those errors.
<?php
// There is a discrepancy between the typehint and the name of the variable
function foo(int $string) { }
// The parameter name is practising coding convention typehints
function bar(int $int) { }
?>
1.2.568.1. Suggestions¶
Synch the name of the parameter and the typehint.
1.2.568.2. Specs¶
Short name |
Functions/MismatchParameterAndType |
Rulesets |
|
Exakat since |
2.1.8 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.569. Mismatch Parameter Name¶
Parameter name change in overwritten method. This may lead to errors when using PHP 8.0 named arguments.
PHP use the name of the parameter in the method whose code is executed. When the name change between the method and the overwritten method, the consistency is broken.
<?php
class x {
function getValue($name) {}
}
class y extends x {
// consistent with the method above
function getValue($name) {}
}
class z extends x {
// inconsistent with the method above
function getValue($label) {}
}
?>
Here is another example, in early PHP 8.0 (courtesy of Carnage).
<?php
interface Pager
{
public function fetch($page = 0, ...$categories);
}
class DbPager implements Pager
{
public function fetch($seite = 0, ...$kategorien)
{
var_dump($kategorien);
}
}
$dbPager = new DbPager();
$dbPager->fetch(page: 1, categories: 2);
?>
1.2.569.1. Suggestions¶
Make sure all the names are the same, between methods
1.2.569.2. Specs¶
Short name |
Functions/MismatchParameterName |
Rulesets |
|
Exakat since |
2.1.8 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.570. Mismatch Type And Default¶
The argument typehint and its default value don’t match.
The code may lint and load, and even work when the arguments are provided. Though, PHP won’t eventually execute it.
Most of the mismatch problems are caught by PHP at linting time. It displays the following error message : ‘Argument 1 passed to foo() must be of the type integer, string given’.
The default value may be a constant (normal or class constant) : as such, PHP might find its value only at execution time, from another include. As such, PHP doesn’t report anything about the situation at compile time.
The default value may also be a constant scalar expression : since PHP 7, some of the simple operators such as +, -, , %, `* <https://www.php.net/manual/en/language.operators.arithmetic.php>`_, etc. are available to build default values. Among them, the ternary operator and Coalesce. Again, those expression may be only evaluated at execution time, when the value of the constants are known.
<?php
// bad definition : the string is actually an integer
const STRING = 3;
function foo(string $s = STRING) {
echo $s;
}
// works without problem
foo('string');
// Fatal error at compile time
foo();
// Fail only at execution time (missing D), and when default is needed
function foo2(string $s = D ? null : array()) {
echo $s;
}
?>
PHP reports typehint and default mismatch at compilation time, unless there is a static expression that can’t be resolved within the compiled file : then it is checked only at runtime, leading to a Fatal error.
See also Type declarations.
1.2.570.1. Suggestions¶
Match the typehint with the default value
Do not rely on PHP type juggling to change the type on the fly
1.2.570.2. Specs¶
Short name |
Functions/MismatchTypeAndDefault |
Rulesets |
|
Exakat since |
1.2.9 |
PHP Version |
All |
Severity |
Critical |
Time To Fix |
Slow (1 hour) |
Precision |
Medium |
Available in |
1.2.571. Mismatched Default Arguments¶
Arguments are relayed from one method to the other, and the arguments have different default values.
Although it is possible to have different default values, it is worth checking why this is actually the case.
<?php
function foo($a = null, $b = array() ) {
// foo method calls directly bar.
// When argument are provided, it's OK
// When argument are omited, the default value is not the same as the next method
bar($a, $b);
}
function bar($c = 1, $d = array() ) {
}
?>
1.2.571.1. Suggestions¶
Synchronize default values to avoid surprises
Drop some of the default values
1.2.571.2. Specs¶
Short name |
Functions/MismatchedDefaultArguments |
Rulesets |
|
Exakat since |
0.12.3 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.572. Mismatched Typehint¶
Relayed arguments don’t have the same typehint.
Typehint acts as a filter method. When an object is checked with a first class, and then checked again with a second distinct class, the whole process is always false : $a can’t be of two different classes at the same time.
<?php
// Foo() calls bar()
function foo(A $a, B $b) {
bar($a, $b);
}
// $a is of A typehint in both methods, but
// $b is of B then BB typehing
function bar(A $a, BB $b) {
}
?>
Note : This analysis currently doesn’t check generalisation of classes : for example, when B is a child of BB, it is still reported as a mismatch.
1.2.572.1. Suggestions¶
Ensure that the default value match the expected typehint.
1.2.572.2. Specs¶
Short name |
Functions/MismatchedTypehint |
Rulesets |
|
Exakat since |
0.12.3 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.573. Missing Typehint¶
No typehint was found for a parameter, a return type for a method or a property.
void is considered a specified typehint, and is not reported here.
<?php
class x {
private $no_property;
function foo($no_typehint) : void {}
function no_return_type() {}
}
?>
See also Type Declaration.
1.2.573.1. Suggestions¶
Add a type to the argument, property or method
1.2.573.2. Specs¶
Short name |
Functions/MissingTypehint |
Rulesets |
|
Exakat since |
2.0.5 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.574. Modified Typed Parameter¶
Reports modified parameters, which have a non-scalar typehint. Such variables should not be changed within the body of the method. Unlike typed properties, which always hold the expected type, typed parameters are only guaranteed type at the beginning of the method block.
<?php
class x {
function foo(Y $y) {
// $y is type Y
// A cast version of $y is stored into $yAsString. $y is untouched.
$yAsString = (string) $y;
// $y is of type 'int', now.
$y = 1;
// Some more code
// display the string version.
echo $yAsString;
// so, Y $y is now raising an error
echo $y->name;
}
}
?>
This problem doesn’t apply to scalar types : by default, PHP pass scalar parameters by value, not by reference. Class types are always passed by reference.
This problem is similar to Don’t Unset Properties : the static specification of the property may be unset, leading to confusing ‘undefined property’, while the class hold the property definition.
1.2.574.1. Suggestions¶
Use different variable names when converting a parameter to a different type.
Only use methods and properties calls on a typed parameter.
1.2.574.2. Specs¶
Short name |
Functions/ModifyTypedParameter |
Rulesets |
|
Exakat since |
2.1.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Available in |
1.2.575. Multiple Functions Declarations¶
Some functions are declared multiple times in the code.
PHP accepts multiple definitions for the same functions, as long as they are not in the same file (linting error), or not included simultaneously during the execution.
This creates to several situations in which the same functions are defined multiple times : the function may be compatible with various PHP version, but their implementation may not. Or the function is part of a larger library, and sometimes only need without the rest of the library.
It is recommended to avoid having several functions with the same name in one repository. Turn those functions into methods and load them when needed.
<?php
namespace a {
function foo() {}
}
// Other file
namespace a {
function foo() {}
function bar() {}
}
?>
1.2.575.1. Specs¶
Short name |
Functions/MultipleDeclarations |
Rulesets |
|
Exakat since |
0.12.0 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.576. Multiple Identical Closure¶
Several closures are defined with the same code.
It may be interesting to check if a named function could be defined from them.
<?php
// the first squares, with closure
$squares= array_map(function ($a) {return $a * $a; }, range(0, 10) );
// later, in another file...
// another identical closure
$squaring = function ($x) { return $x * $x; };
foo($x, $squaring);
?>
This analysis also reports functions and methods that look like the closures : they may be considered for switch.
1.2.576.1. Suggestions¶
Create a function with the body of those closures, and replace the closures by the function’s name.
1.2.576.2. Specs¶
Short name |
Functions/MultipleIdenticalClosure |
Rulesets |
|
Exakat since |
1.5.8 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
Medium |
Available in |
1.2.577. Multiple Returns¶
Functions and methods that have multiple return statement.
This makes it difficult to maintain : since the function may be short-circuited early, some later instruction may be omitted.
Ideally, guard clauses, which check if arguments are valid or not at the beginning of the method are the only exception to this rule.
<?php
function foo() {
// This is a guard clause, that checks arguments.
if ($a < 0) {
return false;
}
$b = 0;
for($i = 0; $i < $a; $i++) {
$b += bar($i);
}
return $b;
}
?>
Currently, the engine doesn’t spot guard clauses.
See also Single Function `Exit Point <http://wiki.c2.com/?SingleFunctionExitPoint>`_.
1.2.577.1. Specs¶
Short name |
Functions/MultipleReturn |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.578. Multiple Definition Of The Same Argument¶
A method’s signature is holding twice (or more) the same argument. For example, function x ($a, $a) { … }.
This is accepted as is by PHP 5, and the last parameter’s value will be assigned to the variable. PHP 7.0 and more recent has dropped this feature, and reports a fatal error when linting the code.
<?php
function x ($a, $a) { print $a; };
x(1,2); => display 2
// special case with a closure :
function ($a) use ($a) { print $a; };
x(1,2); => display 2
?>
However, this is not common programming practise : all arguments should be named differently.
See also Prepare for PHP 7 error messages (part 3).
1.2.578.1. Suggestions¶
Give different names to different parameters
1.2.578.2. Specs¶
Short name |
Functions/MultipleSameArguments |
Rulesets |
CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, All |
Exakat since |
0.8.4 |
PHP Version |
7.0- |
Severity |
Major |
Time To Fix |
Instant (5 mins) |
Precision |
High |
ClearPHP |
|
Available in |
1.2.579. Must Return Methods¶
The following methods are expected to return a value that will be used later. Without return, they are useless.
Methods that must return are : __get(), __isset(), __sleep(), __toString(), __set_state(), __invoke(), __debugInfo(). Methods that may not return, but are often expected to : __call(), __callStatic().
<?php
class foo {
public function __isset($a) {
// returning something useful
return isset($this->$var[$a]);
}
public function __get($a) {
$this->$a++;
// not returning...
}
public function __call($name, $args) {
$this->$name(...$args);
// not returning anything, but that's OK
}
}
?>
1.2.579.1. Suggestions¶
Add a return expression, with a valid data type
Remove the return typehint
1.2.579.2. Specs¶
Short name |
Functions/MustReturn |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.580. Never Called Parameter¶
When a parameter is never used at calltime, it may be turned into a local variable.
It seems that the parameter was set up initially, but never found its practical usage. It is never mentioned, and always fall back on its default value.
Parameter without a default value are reported by PHP, and are usually always filled.
<?php
// $b may be turned into a local var, it is unused
function foo($a, $b = 1) {
return $a + $b;
}
// whenever foo is called, the 2nd arg is not mentionned
foo($a);
foo(3);
foo('a');
foo($c);
?>
1.2.580.1. Suggestions¶
Drop the unused argument in the method definition
Actually use the argument when calling the method
Drop the default value, and check warnings that mention usage of this parameter
See also and .
1.2.580.2. Specs¶
Short name |
Functions/NeverUsedParameter |
Rulesets |
|
Exakat since |
1.0.6 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Examples |
|
Available in |
1.2.581. No Boolean As Default¶
Default values should always be set up with a constant name.
Class constants and constants improve readability when calling the methods or comparing values and statuses.
<?php
const CASE_INSENSITIVE = true;
const CASE_SENSITIVE = false;
function foo($case_insensitive = true) {
// doSomething()
}
// Readable code
foo(CASE_INSENSITIVE);
foo(CASE_SENSITIVE);
// unreadable code : is true case insensitive or case sensitive ?
foo(true);
foo(false);
?>
See also FlagArgument and Clean code: The curse of a boolean parameter.
1.2.581.1. Suggestions¶
Use constants or class constants to give value to a boolean literal
When constants have been defined, use them when calling the code
Split the method into two methods, one for each case
1.2.581.2. Specs¶
Short name |
Functions/NoBooleanAsDefault |
Rulesets |
|
Exakat since |
0.10.0 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.582. No Class As Typehint¶
Avoid using classes as typehint : always use interfaces. This way, different classes, or versions of classes may be passed as argument. The typehint is not linked to an implementation, but to signatures.
A class is needed when the object is with properties : interfaces do not allow the specifications of properties.
<?php
class X {
public $p = 1;
function foo() {}
}
interface i {
function foo();
}
// X is a class : any update in the code requires changing / subclassing X or the rest of the code.
function bar(X $x) {
$x->foo();
}
// I is an interface : X may implements this interface without refactoring and pass
// later, newer versions of X may get another name, but still implement I, and still pass
function bar2(I $x) {
$x->foo();
}
function bar3(I $x) {
echo $x->p;
}
?>
See also Type hinting for interfaces.
1.2.582.1. Suggestions¶
Create an interface with the important methods, and use that interface
Create an abstract class, when public properties are also needed
1.2.582.2. Specs¶
Short name |
Functions/NoClassAsTypehint |
Rulesets |
|
Exakat since |
0.11.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.583. No Literal For Reference¶
Method arguments and return values may be by reference. Then, they need to be a valid variable.
Objects are always passed by reference, so there is no need to explicitly declare it.
Expressions, including ternary operator, produce value, and can’t be used by reference directly. This is also the case for expression that include one or more reference.
<?php
// variables, properties, static properties, array items are all possible
$a = 1;
foo($a);
//This is not possible, as a literal can't be a reference
foo(1);
function foo(&$int) { return $int; }
// This is not a valid reference
function &bar() { return 2; }
function &bar2() { return 2 + $r; }
?>
Wrongly passing a value as a reference leads to a PHP Notice.
See also References.
1.2.583.1. Suggestions¶
Remove the reference in the method signature (argument or return value)
Make the argument an object, by using a typehint (non-scalar)
Put the value into a variable prior to call (or return) the method
1.2.583.2. Specs¶
Short name |
Functions/NoLiteralForReference |
Rulesets |
|
Exakat since |
1.9.5 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.584. No Referenced Void¶
There is no point returning a reference with a void type. This is now reported as deprecated in PHP 8.1.
<?php
function &test(): void {}
?>
See also PHP RFC: Deprecations for PHP 8.1.
1.2.584.1. Suggestions¶
Removes the reference operator from the function definition
1.2.584.2. Specs¶
Short name |
Functions/NoReferencedVoid |
Rulesets |
|
Exakat since |
2.2.4 |
PHP Version |
With PHP 9.0 and older |
PHP deprecated |
8.1 |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
Very high |
Available in |
1.2.585. No Return Used¶
The return value of the following functions are never used. The return argument may be dropped from the code, as it is dead code.
This analysis supports functions and static methods, when a definition may be found. It doesn’t support method calls.
<?php
function foo($a = 1;) { return 1; }
foo();
foo();
foo();
foo();
foo();
foo();
// This function doesn't return anything.
function foo2() { }
// The following function are used in an expression, thus the return is important
function foo3() { return 1;}
function foo4() { return 1;}
function foo5() { return 1;}
foo3() + 1;
$a = foo4();
foo(foo5());
?>
1.2.585.1. Suggestions¶
Remove the return statement in the function
Actually use the value returned by the method, for test or combination with other values
1.2.585.2. Specs¶
Short name |
Functions/NoReturnUsed |
Rulesets |
|
Exakat since |
0.11.3 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Examples |
|
Available in |
1.2.586. Nullable With Constant¶
Arguments are automatically nullable with a literal null. They used to also be nullable with a constant null, before PHP 8.0.
<?php
// Extracted from https://github.com/php/php-src/blob/master/UPGRADING
// Replace
function test(int $arg = CONST_RESOLVING_TO_NULL) {}
// With
function test(?int $arg = CONST_RESOLVING_TO_NULL) {}
// Or
function test(int $arg = null) {}
?>
1.2.586.2. Specs¶
Short name |
Functions/NullableWithConstant |
Rulesets |
|
Exakat since |
2.1.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.587. Nullable Without Check¶
Nullable typehinted argument should be checked before usage.
<?php
// This will emit a fatal error when $a = null
function foo(?A $a) {
return $a->m();
}
// This is stable
function foo(?A $a) {
if ($a === null) {
return 42;
} else {
return $a->m();
}
}
?>
1.2.587.2. Specs¶
Short name |
Functions/NullableWithoutCheck |
Rulesets |
|
Exakat since |
2.0.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.588. One Letter Functions¶
One letter functions seems to be really short for a meaningful name. This may happens for very high usage functions, so as to keep code short, but such functions should be rare.
<?php
// Always use a meaningful name
function addition($a, $b) {
return $a + $b;
}
// One letter functions are rarely meaningful
function f($a, $b) {
return $a + $b;
}
?>
1.2.588.1. Suggestions¶
Use full names for functions
Remove the function name altogether : use a closure
1.2.588.2. Specs¶
Short name |
Functions/OneLetterFunctions |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.589. Only Variable For Reference¶
When a method is requesting an argument to be a reference, it cannot be called with a literal value.
The call must be made with a variable, or any assimilated data container : array, property or static property.
<?php
// This is not possible
foo(1,2);
// This is working
foo($a, $b);
function foo($a, &$b) {}
?>
Note that PHP may detect this error at linting time, if the method is defined after being called : at that point, PHP will only check the problem during execution. This is definitely the case for methods, compared to functions or static methods.
See also Passing arguments by reference.
1.2.589.1. Suggestions¶
Put the literal value in a variable before calling the method.
Omit the arguments, when it won’t be used.
1.2.589.2. Specs¶
Short name |
Functions/OnlyVariableForReference |
Rulesets |
|
Exakat since |
1.4.6 |
PHP Version |
All |
Severity |
Critical |
Time To Fix |
Quick (30 mins) |
Precision |
Medium |
Available in |
1.2.590. Only Variable Passed By Reference¶
When an argument is expected by reference, it is compulsory to provide a container. A container may be a variable, an array, a property or a static property.
This may be linted by PHP, when the function definition is in the same file as the function usage. This is silently linted if definition and usage are separated, if the call is dynamical or made as a method.
<?php
function foo(&$bar) { /**/ }
function &bar() { /**/ }
// This is not possible : strtolower() returns a value
foo(strtolower($string));
// This is valid : bar() returns a reference
foo(bar($string));
?>
This analysis currently covers functioncalls and static methodcalls, but omits methodcalls.
1.2.590.1. Suggestions¶
Store the previous result in a variable, and then call the function.
1.2.590.2. Specs¶
Short name |
Functions/OnlyVariablePassedByReference |
Rulesets |
|
Exakat since |
0.11.3 |
PHP Version |
All |
Severity |
Critical |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Examples |
|
Available in |
1.2.591. Optional Parameter¶
An optional parameter is a method argument that has both a typehint and a default value.
Such argument is optional, as it may be omitted. When this is the case, the code has to differentiate between the default behavior or the actual usage. It is recommended to avoid providing a default value, and use a null object.
<?php
class foo {
function methodWithOptionalArgument(bar $x = null) {
if ($x === null) {
// default behavior
} else {
// normal behavior
}
}
function methodWithCompulsoryArgument(bar $x) {
// normal behavior
// $x is always a bar.
}
}
?>
1.2.591.1. Specs¶
Short name |
Functions/OptionalParameter |
Rulesets |
|
Exakat since |
0.12.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.592. Parameter Hiding¶
When a parameter is set to another variable, and never used.
While this is a legit syntax, parameter hiding tends to make the code confusing. The parameter itself seems to be unused, while some extra variable appears.
Keep this code simple by removing the hiding parameter.
<?php
function substract($a, $b) {
// $b is given to $c;
$c = $b;
$c is used, but $b would be the same
return $a - $c;
}
?>
1.2.592.1. Suggestions¶
Remove the hiding parameter
1.2.592.2. Specs¶
Short name |
Functions/ParameterHiding |
Rulesets |
|
Exakat since |
1.9.8 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.593. Prefix And Suffixes With Typehint¶
This analysis checks the relationship between methods prefixes and suffixes, with their corresponding return typehint.
For example, a method with the signature function isACustomer() {} should return a boolean. That boolean can then be read when calling the method : if ($user->isACustomer()) {}.
There are multiple such conventions that may be applied. For example, has* should return a boolean, set* should return nothing (a.k.a void), and get* shall return any kind of type.
<?php
class x {
// Easy to read convention
function isAUser() : bool {}
// shall return a boolean
function isACustomer() {}
// shall return a string, based on suffix 'name => string'
function getName() {}
// shall return a string, based on suffix 'name => string'
function getUsername() {}
// shall return \Uuid, based on prefix 'uuid => \Uuid'
function getUuid() {}
// shall return anything, based on no prefix nor suffix
function getBirthday() {}
}
?>
There are 2 parameters for this analysis. It is recommended to customize them to get an better results, related to the naming conventions used in the code.
prefixedType is used for prefix in method names, which is the beginning of the name. suffixedType is used for suffixes : the ending part of the name. Matching is case insensitive.
The prefix is configured as the index of the map, while the related type is configured as the value of the map.
prefixToType['is'] = 'bool'; will be use as is* shall use the bool typehint.
Multiple typehints may be used at the same time. PHP supports multiple types since PHP 8.0, and Exakat will support them with any PHP version. Specify multiple types by separating them with comma. Any typehint not found in this list will be reported, including null.
PHP scalar types are available : string, int, void, etc. Explicit types, based on classes or interfaces, must use the fully qualified name, not the short name. suffixToType['uuid'] = '\Uuid'; will be use as *uuid shall use the \Uuid typehint.
When multiple rules applies, only one is reported.
Name |
Default |
Type |
Description |
prefixedType |
prefixedType[‘is’] = ‘bool’; prefixedType[‘has’] = ‘bool’; prefixedType[‘set’] = ‘void’; prefixedType[‘list’] = ‘array’; |
ini_hash |
List of prefixes and their expected returntype |
suffixedType |
prefixedType[‘list’] = ‘bool’; prefixedType[‘int’] = ‘int’; prefixedType[‘string’] = ‘string’; prefixedType[‘name’] = ‘string’; prefixedType[‘description’] = ‘string’; prefixedType[‘id’] = ‘int’; prefixedType[‘uuid’] = ‘Uuid’; |
ini_hash |
List of suffixes and their expected returntype |
1.2.593.1. Specs¶
Short name |
Functions/PrefixToType |
Rulesets |
|
Exakat since |
2.1.1 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.594. Real Functions¶
Real functions, not methods.
Function keywords, that are not in a class, trait, interface, nor a closure.
<?php
// a real Function
function realFunction () {}
// Those are not real functions
function ($closure) { }
class foo {
function isAClassMethod() {}
}
interface fooi {
function isAnInterfaceMethod() {}
}
trait foot {
function isATraitMethod() {}
}
?>
1.2.594.1. Specs¶
Short name |
Functions/RealFunctions |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.595. Recursive Functions¶
Recursive functions are functions that calls itself.
<?php
// a recursive function ; it calls itself
function factorial($n) {
if ($n == 1) { return 1; }
return factorial($n - 1) * $n;
}
?>
Methods are not handled here.
1.2.595.1. Specs¶
Short name |
Functions/Recursive |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.596. Redeclared PHP Functions¶
Function that bear the same name as a PHP function, and that are declared.
This is useful when managing backward compatibility, like emulating an old function, or preparing for newer PHP versions, like emulating new upcoming function.
<?php
if (version_compare(PHP_VERSION, 7.0) > 0) {
function split($separator, $string) {
return explode($separator, $string);
}
}
print_r( split(' ', '2 3'));
?>
1.2.596.1. Suggestions¶
Check if it is still worth emulating that function
1.2.596.2. Specs¶
Short name |
Functions/RedeclaredPhpFunction |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.597. Relay Function¶
Relay function only delegate workload to another one.
Relay functions and methods are delegating the actual work to another function or method. They do not have any impact on the results, besides exposing another name for the same feature.
<?php
function myStrtolower($string) {
return \strtolower($string);
}
?>
Relay functions are typical of transition API, where an old API have to be preserved until it is fully migrated. Then, they may be removed, so as to reduce confusion, and simplify the API.
1.2.597.1. Suggestions¶
Remove relay function, call directly the final function
Remove the target function, and move the code here
Add more logic to that function, like conditions or cache
1.2.597.2. Specs¶
Short name |
Functions/RelayFunction |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.598. Semantic Typing¶
Arguments names are only useful inside the method’s body. They are not actual type.
<?php
// arguments should be a string and an array
function foo($array, $str) {
// more code
return $boolean;
}
// typehint is actually checking the values
function bar(iterable $closure) : bool {
// more code
return true;
}
?>
1.2.598.1. Suggestions¶
Use a typehint to make sure the argument is of the expected type.
1.2.598.2. Specs¶
Short name |
Functions/SemanticTyping |
Rulesets |
|
Exakat since |
2.0.5 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.599. Argument Should Be Typehinted¶
When a method expects objects as argument, those arguments should be typehinted. This way, it provides early warning that a wrong object is being sent to the method.
The analyzer will detect situations where a class, or the keywords ‘array’ or ‘callable’.
<?php
// What are the possible classes that have a 'foo' method?
function foo($bar) {
return $bar->foo();
}
?>
Closure arguments are omitted.
See also Type declarations.
1.2.599.1. Suggestions¶
Add the typehint to the function arguments
1.2.599.2. Specs¶
Short name |
Functions/ShouldBeTypehinted |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
ClearPHP |
|
Examples |
|
Available in |
1.2.600. Should Use Constants¶
The following functions have related constants that should be used as arguments, instead of scalar literals, such as integers or strings.
<?php
// The file is read and new lines are ignored.
$lines = file('file.txt', FILE_IGNORE_NEW_LINES)
// What is this doing, with 2 ?
$lines = file('file.txt', 2);
?>
See also Bitmask Constant Arguments in PHP.
1.2.600.1. Suggestions¶
Use PHP native constants whenever possible, for better readability.
1.2.600.2. Specs¶
Short name |
Functions/ShouldUseConstants |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.601. Should Yield With Key¶
iterator_to_array() will overwrite generated values with the same key.
PHP generators are based on the yield keyword. They also delegate some generating to other methods, with yield from.
When delegating, yield from uses the keys that are generated with yield, and otherwise, it uses auto-generated index, starting with 0.
The trap is that each yield from reset the index generation and start again with 0. Coupled with iterator_to_array(), this means that the final generated array may lack some values, while a foreach() loop would yield all of them.
<?php
function g1() : Generator {
for ( $i = 0; $i < 4; $i++ ) { yield $i; }
}
function g2() : Generator {
for ( $i = 5; $i < 10; $i++ ) { yield $i; }
}
function aggregator() : Generator {
yield from g1();
yield from g2();
}
print_r(iterator_to_array());
/*
Array
(
[0] => 6
[1] => 7
[2] => 8
[3] => 9
[4] => 4 // Note that 4 and 5 still appears
[5] => 5 // They are not overwritten by the second yield
)
*/
foreach ( aggregator() as $i ) {
print $i.PHP_EOL;
}
/*
0 // Foreach has no overlap and yield it all.
1
2
3
4
5
6
7
8
9
*/
?>
Thanks to Holger Woltersdorf for pointing this.
See also Generator syntax and Yielding values with keys.
1.2.601.1. Suggestions¶
Use iterator_to_array() on each generator separately, and use array_merge() to merge all the arrays.
Always yield with distinct keys
Avoid iterator_to_array() and use foreach()
1.2.601.2. Specs¶
Short name |
Functions/ShouldYieldWithKey |
Rulesets |
|
Exakat since |
1.5.2 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.602. Too Many Local Variables¶
Too many local variables were found in the methods. When over 15 variables are found in such a method, a violation is reported.
Local variables exclude globals (imported with global) and arguments. Local variable include static variables.
When too many variables are used in a function, it is a code smells. The function is trying to do too much and needs extra space for juggling. Beyond 15 variables, it becomes difficult to keep track of their name and usage, leading to confusion, overwriting or hijacking.
<?php
// This function is OK : 3 vars are arguments, 3 others are globals.
function a20a3g3($a1, $a2, $a3) {
global $a4, $a5, $a6;
$a1 = 1;
$a2 = 2;
$a3 = 3 ;
$a4 = 4 ;
$a5 = 5 ;
$a6 = 6 ;
$a7 = 7 ;
$a8 = 8 ;
$a9 = 9 ;
$a10 = 10;
$a11 = 11;
$a12 = 12;
$a13 = 13 ;
$a14 = 14 ;
$a15 = 15 ;
$a16 = 16 ;
$a17 = 17 ;
$a18 = 18 ;
$a19 = 19 ;
$a20 = 20;
}
// This function has too many variables
function a20() {
$a1 = 1;
$a2 = 2;
$a3 = 3 ;
$a4 = 4 ;
$a5 = 5 ;
$a6 = 6 ;
$a7 = 7 ;
$a8 = 8 ;
$a9 = 9 ;
$a10 = 10;
$a11 = 11;
$a12 = 12;
$a13 = 13 ;
$a14 = 14 ;
$a15 = 15 ;
$a16 = 16 ;
$a17 = 17 ;
$a18 = 18 ;
$a19 = 19 ;
$a20 = 20;
}
?>
1.2.602.1. Suggestions¶
Remove some of the variables, and inline them
Break the big function into smaller ones
Find repeated code and make it a separate function
Name |
Default |
Type |
Description |
tooManyLocalVariableThreshold |
15 |
integer |
Minimal number of variables in one function or method to report. |
1.2.602.2. Specs¶
Short name |
Functions/TooManyLocalVariables |
Rulesets |
|
Exakat since |
0.9.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Examples |
|
Available in |
1.2.603. Too Many Parameters¶
Method has too many parameters. Exakat has a default parameter count which may be configured.
A method that needs more than 8 parameters is trying to do too much : it should be reviewed and split into smaller methods.
<?php
// This methods has too many parameters.
function alertSomeone($name, $email, $title, $message, $attachements, $signature, $bcc, $cc, $extra_headers) {
/* too much code here */
}
?>
See also How many parameters is too many ? and Too Many Parameters.
1.2.603.1. Suggestions¶
Reduce the number of parameters to a lower level
Break the function into smaller functions
Turn the function into a class
Name |
Default |
Type |
Description |
parametersCount |
8 |
integer |
Minimal number of parameters to report. |
1.2.603.2. Specs¶
Short name |
Functions/TooManyParameters |
Rulesets |
|
Exakat since |
1.1.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Examples |
|
Available in |
1.2.604. Too Much Indented¶
Reports methods that are using more than one level of indentation on average.
Indentations levels are counted for each for, foreach, if…then, while, do..while, try..catch..finally structure met. Compulsory expressions, such as conditions, are not counted in the total. Levels of indentation start at 0 (no indentation needed)
This analysis targets methods which are build around large conditions : the actual useful code is nested inside the branches of the if/then/else (for example).
The default threshold indentationAverage of 1 is a good start for spotting large methods with big conditional code, and will leave smaller methods, even when they only contain one if/then. Larger methods shall be refactored in smaller size.
The parameter minimumSize set aside methods which are too small for refactoring.
<?php
// average 0
function foo0() {
$a = rand(1,2);
$a *= 3;
return $a;
}
// average 0.66 = (0 + 1 + 1) / 3
function foo0_66() {
// if () is at level 0
if ($a == 2) { // condition is not counted
$a = 1; // level 1
} else {
$a = 2; // level 1
}
}
// average 1 = (0 + 2 + 1 + 1) / 4
function foo1() {
// if () is at level 0
if ($a == 2) {
// if () is at level 1
if ($a == 2) {
$a = 1; // level 2
}
$a = 1; // level 1
} else {
$a = 2; // level 1
}
}
?>
This analysis is distinct from Structures/MaxLevelOfIdentation, which only reports the highest level of indentation. This one reports how one method is build around one big
See also Max Level Of Nesting.
1.2.604.1. Suggestions¶
Refactor the method to reduce the highest level of indentation
Refactor the method move some of the code to external methods.
Name |
Default |
Type |
Description |
indentationAverage |
1 |
real |
Minimal average of indentation in a method to report. Default is 1.0, which means that the method is on average at one level of indentation or more. |
minimumSize |
3 |
real |
Minimal number of expressions in a method to apply this analysis. |
1.2.604.2. Specs¶
Short name |
Functions/TooMuchIndented |
Rulesets |
|
Exakat since |
2.1.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.605. Typehint Must Be Returned¶
When using a typehint for a method, it is compulsory to use a at least one return in the method’s body. This is true for nullable typehint too :
returnalone won’t be sufficient.
<?php
// The function returns a value (here, correct object)
function foo() : Bar { return new Bar(); }
// The function should at least, return a value
function foo() : Bar { }
// The function should at least, return a value : Null or an object. Void, here, is not acceptable.
function foo() : ?Bar { return; }
?>
PHP lint this, but won’t execute it.
This analysis doesn’t check if the returned value is compatible with the returned typehint. Only its presence is checked.
See also Return Type Declaration and Type hint in PHP function parameters and return values.
1.2.605.1. Suggestions¶
Add a return with a valid value
1.2.605.2. Specs¶
Short name |
Functions/TypehintMustBeReturned |
Rulesets |
|
Exakat since |
1.6.9 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.606. Typehinted References¶
Typehinted arguments have no need for references. Since they are only an object, they are already a reference.
In fact, adding the & on the argument definition may lead to error like Only variables should be passed by reference.
This applies to the object type hint, but not the the others, such as int or bool.
<?php
// a class
class X {
public $a = 3;
}
// typehinted reference
//function foo(object &$x) works too
function foo(X &$x) {
$x->a = 1;
return $x;
}
// Send an object
$y = foo(new X);
// This prints 1;
print $y->a;
?>
See also Passing by reference and Objects and references.
1.2.606.1. Suggestions¶
Remove reference for typehinted arguments, unless the typehint is a scalar typehint.
1.2.606.2. Specs¶
Short name |
Functions/TypehintedReferences |
Rulesets |
|
Exakat since |
1.2.8 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.607. Typehints¶
List of all the types (classes or scalar) used in Typehinting.
<?php
// here, array, myObject and string are all typehints.
function foo(array $array, myObject $x, string $string) {
}
?>
See also Type declarations.
1.2.607.1. Specs¶
Short name |
Functions/Typehints |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.608. Unbinding Closures¶
Never drop
$this, once a closure was created in a non-static method.
From the PHP wiki : Currently it is possible to unbind the $this variable from a closure that originally had one by using $closure->bindTo(null). Due to the removal of static calls to non-static methods in PHP 8, we now have a guarantee that $this always exists inside non-static methods. We would like to have a similar guarantee that $this always exists for non-static closures declared inside non-static methods. Otherwise, we will end up imposing an unnecessary performance penalty either on $this accesses in general, or $this accesses inside such closures.
<?php
class x {
private $a = 3;
function foo() {
return function () { echo $this->a; };
}
}
$closure = (new x)->foo();
// $this was expected, and it is not anymore
$closure->bindTo(null);
$closure->bindTo(new x);
?>
Calling bindTo() with a valid object is still valid.
See also Unbinding `$this from non-static closures <https://wiki.php.net/rfc/deprecations_php_7_4#unbinding_this_from_non-static_closures>`_.
1.2.608.1. Suggestions¶
Create a static closure, which doesn’t rely on $this at all
Remove the call to bindTo(null).
1.2.608.2. Specs¶
Short name |
Functions/UnbindingClosures |
Rulesets |
|
Exakat since |
1.9.0 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.609. Undefined Functions¶
Some functions are called, but not defined in the code. This means that the functions are probably defined in a missing library, or in an extension. If not, this will yield a Fatal error at execution.
<?php
// Undefined function
foo($a);
// valid function, as it belongs to the ext/yaml extension
$parsed = yaml_parse($yaml);
// This function is not defined in the a\b\c namespace, nor in the global namespace
a\b\c\foo();
?>
See also Functions.
1.2.609.1. Suggestions¶
Fix the name of the function in the code
Remove the functioncall in the code
Define the function for the code to call it
Include the correct library in the code source
1.2.609.2. Specs¶
Short name |
Functions/UndefinedFunctions |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.610. Unknown Parameter Name¶
The name of the parameter doesn’t belong to the method signature. Named arguments was introduced in PHP 8.0.
<?php
// All good
foo(a:1, b:2, c:3);
foo(...['a':1, 'b':2, 'c':3]);
// A is not a parameter name, it should be a : names are case sensitive
foo(A:1, b:2, c:3);
foo(...['A':1, 'b':2, 'c':3]);
function foo($a, $b, $c) {}
?>
See also Named Arguments.
1.2.610.1. Suggestions¶
Fix the name of the parameter and use a valid one
Remove the parameter name, and revert to positional notation
1.2.610.2. Specs¶
Short name |
Functions/UnknownParameterName |
Rulesets |
|
Exakat since |
2.1.6 |
PHP Version |
With PHP 8.0 and more recent |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.611. Unset Arguments¶
There is no need to unset arguments. Those values will be freed at the end of the function anyhow.
<?php
function foo($a, $b) {
$b = $a * 2;
// This is useless. $a will be freed at the end of the function.
unset($a);
}
?>
1.2.611.1. Specs¶
Short name |
Functions/UnsetOnArguments |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.612. Unused Arguments¶
Those arguments are not used in the method or function.
Unused arguments should be removed in functions : they are just dead code.
Unused argument may have to stay in methods, as the signature is actually defined in the parent class.
<?php
// $unused is in the signature, but not used.
function foo($unused, $b, $c) {
return $b + $c;
}
?>
1.2.612.1. Suggestions¶
Drop the argument from the signature
Actually use that argument in the body of the method
1.2.612.2. Specs¶
Short name |
Functions/UnusedArguments |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.613. Unused Functions¶
The functions below are unused. They look like dead code.
Recursive functions, level 1, are detected : they are only reported when a call from outside the function is made. Recursive functions calls of higher level (A calls B calls A) are not handled.
<?php
function used() {}
// The 'unused' function is defined but never called
function unused() {}
// The 'used' function is called at least once
used();
?>
1.2.613.1. Suggestions¶
Use the function in the code
Remove the functions from the code
1.2.613.2. Specs¶
Short name |
Functions/UnusedFunctions |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.614. Unused Inherited Variable In Closure¶
Some closures forgot to make usage of inherited variables.
Closure have two separate set of incoming variables : the arguments (between parenthesis) and the inherited variables, in the ‘use’ clause. Inherited variables are extracted from the local environment at creation time, and keep their value until execution.
The reported closures are requesting some local variables, but do not make any usage of them. They may be considered as dead code.
<?php
// In this closure, $y is forgotten, but $u is used.
$a = function ($y) use ($u) { return $u; };
// In this closure, $u is forgotten
$a = function ($y, $z) use ($u) { return $u; };
?>
See also Anonymous functions.
1.2.614.1. Suggestions¶
Remove the unused inherited variable
Make us of the unused inherited variable
1.2.614.2. Specs¶
Short name |
Functions/UnusedInheritedVariable |
Rulesets |
|
Exakat since |
1.0.11 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.615. Unused Returned Value¶
The function called returns a value, which is ignored.
Usually, this is a sign of dead code, or a missed check on the results of the functioncall. At times, it may be a valid call if the function has voluntarily no return value.
It is recommended to add a check on the return value, or remove the call.
<?php
// simplest form
function foo() {
return 1;
}
foo();
// In case of multiple return, any one that returns something means that return value is meaningful
function bar() {
if (rand(0, 1)) {
return 1;
} else {
return ;
}
}
bar();
?>
Note that this analysis ignores functions that return void (same meaning that PHP 7.1 : return ; or no return in the function body).
1.2.615.1. Specs¶
Short name |
Functions/UnusedReturnedValue |
Rulesets |
|
Exakat since |
0.8.5 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.616. Use Arrow Functions¶
Arrow functions are closures that require less code to write.
Arrow functions were introduced in PHP 7.4. They added the reserved keyword fn. s
<?php
array_map(fn(A $b): int => $b->c, $array);
function array_values_from_keys($arr, $keys) {
return array_map(fn($x) => $arr[$x], $keys);
}
?>
See also RFC : Arrow functions and Arrow functions in PHP.
1.2.616.1. Specs¶
Short name |
Functions/UseArrowFunctions |
Rulesets |
|
Exakat since |
1.9.4 |
PHP Version |
7.4+ |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Available in |
1.2.617. Use Constant As Arguments¶
Some methods and functions are defined to be used with constants as arguments. Those constants are made to be meaningful and readable, keeping the code maintenable. It is recommended to use such constants as soon as they are documented.
<?php
// Turn off all error reporting
// 0 and -1 are accepted
error_reporting(0);
// Report simple running errors
error_reporting(E_ERROR | E_WARNING | E_PARSE);
// The first argument can be one of INPUT_GET, INPUT_POST, INPUT_COOKIE, INPUT_SERVER, or INPUT_ENV.
$search_html = filter_input(INPUT_GET, 'search', FILTER_SANITIZE_SPECIAL_CHARS);
// sort accepts one of SORT_REGULAR, SORT_NUMERIC, SORT_STRING, SORT_LOCALE_STRING, SORT_NATURAL
// SORT_FLAG_CASE may be added, and combined with SORT_STRING or SORT_NATURAL
sort($fruits);
?>
Here is the list of function that use a unique PHP constant as argument :
dns_get_record()
Here is the list of functions that use a combination of PHP native functions as argument.
1.2.617.1. Suggestions¶
Use PHP native constants, whenever possible, instead of meaningless literals.
1.2.617.2. Specs¶
Short name |
Functions/UseConstantAsArguments |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.618. Used Functions¶
The functions below are used in the code.
A function is used in the code when it is called literally, or as a string callback.
<?php
function used() {}
// The 'unused' function is defined but never called
function unused() {}
// The 'used' function is called at least once
used();
// The 'used' function is called as a callback
array_filter($array, 'used');
?>
1.2.618.1. Specs¶
Short name |
Functions/UsedFunctions |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.619. Useless Argument¶
The argument is always used with the same value. This value could be hard coded in the method, and save one argument slot.
There is no indication that this argument will be used with other values. It may be a development artifact, that survived without cleaning.
<?php
// All foo2 arguments are used with different values
function foo2($a, $b) {}
foo2(1, 2);
foo2(2, 2);
foo2(3, 3);
// The second argument of foo is always used with 2
function foo($a, $b) {}
foo(1, 2);
foo(2, 2);
foo(3, 2);
?>
Methods with less than 3 calls are not considered here, to avoid reporting methods used once. Also, arguments with a default value are omitted.
The chances of useless arguments decrease with the number of usage. The parameter maxUsageCount prevents highly called methods (more than the parameter value) to be processed.
1.2.619.1. Suggestions¶
Remove the argument and hard code its value inside the method
Add the value as default in the method signature, and drop it from the calls
Add calls to the method, with more varied arguments
Name |
Default |
Type |
Description |
maxUsageCount |
30 |
integer |
Maximum count of function usage. Use this to limit the amount of processed arguments. |
1.2.619.2. Specs¶
Short name |
Functions/UselessArgument |
Rulesets |
|
Exakat since |
1.8.0 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.620. Useless Default Argument¶
One of the argument has a default value, and this default value is never used. Every time the method is called, the argument is provided explicitly, rendering the default value actually useless.
<?php
function goo($a, $b = 3) {
// do something here
}
// foo is called 3 times, and sometimes, $b is not provided.
goo(1,2);
goo(1,2);
goo(1);
function foo($a, $b = 3) {
// do something here
}
// foo is called 3 times, and $b is always provided.
foo(1,2);
foo(1,2);
foo(1,2);
?>
1.2.620.1. Suggestions¶
Remove the default value
Remove the explicit argument in the function call, when it is equal to the default value
1.2.620.2. Specs¶
Short name |
Functions/UselessDefault |
Rulesets |
|
Exakat since |
1.7.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.621. Useless Referenced Argument¶
The argument has a reference, but is only used for reading.
This is probably a development artefact that was forgotten. It is better to remove it.
This analysis also applies to foreach() loops, that declare the blind variable as reference, then use the variable as an object, accessing properties and methods. When a variable contains an object, there is no need to declare a reference : it is a reference automatically.
<?php
function foo($a, &$b, &$c) {
// $c is passed by reference, but only read. The reference is useless.
$b = $c + $a;
// The reference is useful for $b
}
foreach ($array as &$element) {
$element->method();
}
?>
See also Objects and references.
1.2.621.1. Suggestions¶
Remove the useless & from the argument
Make an actual use of the argument before the end of the method
1.2.621.2. Specs¶
Short name |
Functions/UselessReferenceArgument |
Rulesets |
|
Exakat since |
1.1.3 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Examples |
|
Available in |
1.2.622. Useless Return¶
The spotted functions or methods have a return statement, but this statement is useless. This is the case for constructor and destructors, whose return value are ignored or inaccessible.
When return is void, and the last element in a function, it is also useless.
<?php
class foo {
function __construct() {
// return is not used by PHP
return 2;
}
}
function bar(&$a) {
$a++;
// The last return, when empty, is useless
return;
}
?>
1.2.622.1. Suggestions¶
Remove the return expression. Keep any other calculation.
1.2.622.2. Specs¶
Short name |
Functions/UselessReturn |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
Very high |
Examples |
|
Available in |
1.2.623. Useless Type Check¶
With typehint, some checks on the arguments are now handled by the type system.
In particular, a type hinted argument can’t be null, unless it is explicitly nullable, or has a null value as default.
<?php
// The test on null is useless, it will never happen
function foo(A $a) {
if (is_null($a)) {
// do something
}
}
// Either nullable ? is too much, either the default null is
function barbar(?A $a = null) {
}
// The test on null is useful, the default value null allows it
function bar(A $a = null) {
if ($a === null) {
// do something
}
}
?>
1.2.623.1. Suggestions¶
Remove the nullable typehint
Remove the null default value
Remove tests on null
See also and Type Declarations.
1.2.623.2. Specs¶
Short name |
Functions/UselessTypeCheck |
Rulesets |
|
Exakat since |
1.8.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Available in |
1.2.624. Uses Default Values¶
Default values are provided to methods so as to make it convenient to use. However, with new versions, those values may change. For example, in PHP 5.4, htmlentities() switched from
Latin1toUTF-8default encoding.
<?php
$string = Eu não sou o pão;
echo htmlentities($string);
// PHP 5.3 : Eu não sou o pão
// PHP 5.4 : Eu não sou o pão
// Stable across versions
echo htmlentities($string, 'UTF8');
?>
As much as possible, it is recommended to use explicit values in those methods, so as to prevent from being surprise at a future PHP evolution.
This analyzer tend to report a lot of false positives, including usage of count(). Count() indeed has a second argument for recursive counts, and a default value. This may be ignored safely.
1.2.624.2. Specs¶
Short name |
Functions/UsesDefaultArguments |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Available in |
1.2.625. Using Deprecated Method¶
A call to a deprecated method has been spotted. A method is deprecated when it bears a
@deprecatedparameter in its typehint definition.
Deprecated methods which are not called are not reported.
<?php
// not deprecated method
not_deprecated();
// deprecated methods
deprecated();
$object = new X();
$object->deprecatedToo();
/**
* @deprecated since version 2.0.0
*/
function deprecated() {}
// PHP 8.0 attribute for deprecation
class X {
#[ Deprecated]
function deprecatedToo() {}
}
function not_deprecated() {}
?>
See also @deprecated.
1.2.625.1. Suggestions¶
Replace the deprecated call with a stable call
Remove the deprecated attribute from the method definition
Remove the deprecated call
1.2.625.2. Specs¶
Short name |
Functions/UsingDeprecated |
Rulesets |
|
Exakat since |
2.1.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.626. Has Variable Arguments¶
Indicates if this function or method accept an arbitrary number of arguments, based on func_get_args(), func_get_arg() and func_num_args() usage.
<?php
// Fixed number of arguments
function fixedNumberOfArguments($a, $b) {
if (func_num_args() > 2) {
$c = func_get_args();
array_shift($c); // $a
array_shift($c); // $b
}
// do something
}
// Fixed number of arguments
function fixedNumberOfArguments($a, $b, $c = 1) {}
?>
1.2.626.1. Specs¶
Short name |
Functions/VariableArguments |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
Very high |
Available in |
1.2.627. Methods Without Return¶
List of all the function, closures, methods that have no explicit return.
Functions that hold the void return type are omitted.
<?php
// With return null : Explicitly not returning
function withExplicitReturn($a = 1) {
$a++;
return null;
}
// Without indication
function withoutExplicitReturn($a = 1) {
$a++;
}
// With return type void : Explicitly not returning
function withExplicitReturnType($a = 1) : void {
$a++;
}
?>
See also return.
1.2.627.1. Suggestions¶
Add the returntype ‘void’ to make this explicit behavior
1.2.627.2. Specs¶
Short name |
Functions/WithoutReturn |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Available in |
1.2.628. Wrong Argument Name With PHP Function¶
The name of the argument provided is not a valid parameter name for that PHP function. Named arguments also works with PHP native function.
<?php
// those are the valid names
strcmp(string1: 'a', string2: 'b');
// those are not the valid names
strcmp(string: 'a', stringToo: 'b');
?>
1.2.628.1. Suggestions¶
Use the correct parameter name
Remove all the parameter names from the call
Create a relay function with the correct parameter names
1.2.628.2. Specs¶
Short name |
Functions/WrongArgumentNameWithPhpFunction |
Rulesets |
|
Exakat since |
2.2.3 |
PHP Version |
With PHP 8.0 and more recent |
Severity |
Major |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.629. Wrong Argument Type¶
Checks that the type of the argument is consistent with the type of the called method.
<?php
function foo(int $a) { }
//valid call, with an integer
foo(1);
//invalid call, with a string
foo('asd');
?>
This analysis is valid with PHP 8.0.
1.2.629.1. Suggestions¶
Always use a valid type when calling methods.
1.2.629.2. Specs¶
Short name |
Functions/WrongArgumentType |
Rulesets |
|
Exakat since |
2.1.3 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.630. Wrong Function Name Case¶
The spotted functions are used with a different case than their definition. While PHP accepts this, it makes the code harder to read.
It may also be a violation of coding conventions.
<?php
// Definition of the class
function foo () {}
// Those calls have wrong case
FOO();
\Foo();
// This is valid
foo();
?>
See also PHP class name constant case sensitivity and PSR-11.
1.2.630.1. Suggestions¶
Match the defined functioncall with the called name
1.2.630.2. Specs¶
Short name |
Functions/WrongCase |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.631. Wrong Number Of Arguments¶
Those functioncalls are made with too many or too few arguments.
When the number arguments is wrong for native functions, PHP emits a warning. When the number arguments is too small for custom functions, PHP raises an exception. When the number arguments is too high for custom functions, PHP ignores the arguments. Such arguments should be handled with the variadic operator, or with func_get_args() family of functions.
<?php
echo strtoupper('This function is', 'ignoring arguments');
//Warning: strtoupper() expects exactly 1 parameter, 2 given in Command line code on line 1
echo strtoupper();
//Warning: strtoupper() expects exactly 1 parameter, 0 given in Command line code on line 1
function foo($argument) {}
echo foo();
//Fatal error: Uncaught ArgumentCountError: Too few arguments to function foo(), 0 passed in /Users/famille/Desktop/analyzeG3/test.php on line 10 and exactly 1 expected in /Users/famille/Desktop/analyzeG3/test.php:3
echo foo('This function is', 'ignoring arguments');
?>
It is recommended to check the signature of the methods, and fix the arguments.
1.2.631.1. Suggestions¶
Add more arguments to fill the list of compulsory arguments
Remove arguments to fit the list of compulsory arguments
Use another method or class
1.2.631.2. Specs¶
Short name |
Functions/WrongNumberOfArguments |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
ClearPHP |
|
Examples |
|
Available in |
1.2.632. Wrong Number Of Arguments In Methods¶
Those methods are called with a wrong number of arguments : too many or too few. Check the signature.
<?php
class Foo {
private function Bar($a, $b) {
return $a + $b;
}
public function foobar() {
$this->Bar(1);
// Good amount
$this->Bar(1, 2);
// Too Many
$this->Bar(1, 2, 3);
}
}
?>
Methods with a variable number of argument, either using ellipsis or func_get_args() are ignored.
PHP emits an error at runtime, when arguments are not enough : ‘’. PHP doesn’t emit an error when too many arguments are provided.
1.2.632.1. Suggestions¶
Adapt the call to use one of the right number of arguments : this means dropping the extra ones, or adding the missing ones
Adapt the signature of the method, and use a default value
1.2.632.2. Specs¶
Short name |
Functions/WrongNumberOfArgumentsMethods |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.633. Wrong Optional Parameter¶
Wrong placement of optional parameters.
PHP parameters are optional when they defined with a default value, like this :
<?php
function x($arg = 1) {
// PHP code here
}
?>
When a function have both compulsory and optional parameters, the compulsory ones should appear first, and the optional should appear last :
<?php
function x($arg, $arg2 = 2) {
// PHP code here
}
?>
PHP solves this problem at runtime, assign values in the same other, but will miss some of the default values and emits warnings.
It is better to put all the optional parameters at the end of the method’s signature.
Optional parameter wrongly placed are now a Notice in PHP 8.0. The only previous case that is allowed in PHP 8.0 and also in this analysis, is when the null value is used as default for typed arguments.
See also Function arguments.
1.2.633.1. Suggestions¶
Give default values to all but first parameters. Null is a good default value, as PHP will use it if not told otherwise.
Remove default values to all but last parameters. That is probably a weak solution.
Change the order of the values, so default-valued parameters are at the end. This will probably have impact on the rest of the code, as the API is changing.
1.2.633.2. Specs¶
Short name |
Functions/WrongOptionalParameter |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.634. Wrong Type Returned¶
The returned value is not compatible with the specified return type.
<?php
// classic error
function bar() : int {
return 'A';
}
// classic static error
const B = 2;
function bar() : string {
return B;
}
// undecideable error
function bar($c) : string {
return $c;
}
// PHP lint this, but won't execute it
function foo() : void {
// No return at all
}
?>
See also Returning values and Void Return Type.
1.2.634.1. Suggestions¶
Match the return type with the return value
Remove the return expression altogether
Add a typecast to the returning expression
1.2.635. Wrong Type With Call¶
This analysis checks that a call to a method uses the right literal values’ types.
Currently, this analysis doesn’t take into account strict_types = 1.
This analysis is compatible with Union types and with Intersection types.
<?php
function foo(string $a) {
}
// wrong type used
foo(1);
// wrong type used
foo("1");
?>
1.2.635.1. Suggestions¶
Use the right type with all arguments
1.2.636. Wrong Typehinted Name¶
The parameter name doesn’t reflect the typehint used.
There are no restriction on parameter names, except its uniqueness in the signature. Yet, using a scalar typehint as the name for another typehinted value is just misleading.
<?php
function foo(string $array,
int $int) {
// doSomething()
}
function bar(array $strings) {
// doSomething()
}
?>
This analysis relies on exact names : calling an array a list of strings is OK with this analysis.
This analysis relies on a few variations of names : bool and boolean, int and integer.
1.2.636.2. Specs¶
Short name |
Functions/WrongTypehintedName |
Rulesets |
|
Exakat since |
2.0.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.637. func_get_arg() Modified¶
func_get_arg() and func_get_args() used to report the calling value of the argument until PHP 7. Since PHP 7, it is reporting the value of the argument at calling time, which may have been modified by a previous instruction.
<?php
function x($a) {
$a++;
print func_get_arg(0);
}
x(0);
?>
This code will display 1 in PHP 7, and 0 in PHP 5.
1.2.637.1. Specs¶
Short name |
Functions/funcGetArgModified |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.638. Already Parents Interface¶
The same interface is implemented by a class and one of its children.
That way, the child doesn’t need to implement the interface, nor define its methods to be an instance of the interface.
<?php
interface i {
function i();
}
class A implements i {
function i() {
return __METHOD__;
}
}
// This implements is useless.
class AB extends A implements i {
// No definition for function i()
}
// Implements i is understated
class AB extends A {
// redefinition of the i method
function i() {
return __METHOD__.' ';
}
}
$x = new AB;
var_dump($x instanceof i);
// true
$x = new AC;
var_dump($x instanceof i);
// true
?>
1.2.638.1. Suggestions¶
Keep the implements call in the class that do implements the methods. Remove it from the children classes.
1.2.638.2. Specs¶
Short name |
Interfaces/AlreadyParentsInterface |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
Very high |
Examples |
|
Available in |
1.2.639. Avoid Self In Interface¶
self refers to the current interface or its extended parents : as long as the constant is defined in the interface family, this is valid. On the other hand, when self refers to the current class, the resolution of names will happen at execution time, leading to confusing results.
parent has the same behavior than self, except that it doesn’t accept to be used inside an interface, as it will yield an error. This is one of those error that lint but won’t execute in certain conditions.
Static can’t be used in an interface, as it needs to be resolved at call time anyway.
<?php
interface i extends ii {
// This 'self' is valid : it refers to the interface i
public const I = self::I2 + 2;
// This 'self' is also valid, as it refers to interface ii, which is a part of interface i
public const I2 = self::IP + 4;
// This makes interface i dependant on the host class
public const I3 = parent::A;
}
?>
See also Scope Resolution Operator (::).
1.2.639.1. Suggestions¶
Use a fully qualified namespace instead of self
Use a locally defined constant, so self is a valid reference
1.2.639.2. Specs¶
Short name |
Interfaces/AvoidSelfInInterface |
Rulesets |
|
Exakat since |
1.5.4 |
PHP Version |
All |
Severity |
Critical |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.640. Cant Implement Traversable¶
It is not possible to implement the
Traversable``interface. The alternative is to implement ``IteratororIteratorAggregate.
Traversable may be useful when used with instanceof.
<?php
// This lints, but doesn't run
class x implements Traversable {
}
if( $argument instanceof Traversable ) {
// doSomething
}
?>
See also Traversable, Iterator and IteratorAggregate..
1.2.640.1. Suggestions¶
Implement Iterator or IteratorAggregate
1.2.640.2. Specs¶
Short name |
Interfaces/CantImplementTraversable |
Rulesets |
|
Exakat since |
1.9.8 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.641. Concrete Visibility¶
Methods that implements an interface in a class must be public.
PHP does lint this, unless the interface and the class are in the same file. At execution, it stops immediately with a Fatal error : ‘Access level to c::iPrivate() must be public (as in class i) ‘;
<?php
interface i {
function iPrivate() ;
function iProtected() ;
function iPublic() ;
}
class c implements i {
// Methods that implements an interface in a class must be public.
private function iPrivate() {}
protected function iProtected() {}
public function iPublic() {}
}
?>
See also Interfaces.
1.2.641.1. Suggestions¶
Always set interface methods to public.
1.2.641.2. Specs¶
Short name |
Interfaces/ConcreteVisibility |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.642. Forgotten Interface¶
The following classes have been found implementing an interface’s methods, though it doesn’t explicitly implements this interface. This may have been forgotten.
<?php
interface i {
function i();
}
// i is not implemented and declared
class foo {
function i() {}
function j() {}
}
// i is implemented and declared
class foo implements i {
function i() {}
function j() {}
}
?>
See also Could Use Trait.
1.2.642.1. Suggestions¶
Mention interfaces explicitly whenever possible
1.2.642.2. Specs¶
Short name |
Interfaces/CouldUseInterface |
Rulesets |
|
Exakat since |
0.11.7 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.643. Empty Interfaces¶
Empty interfaces are a code smell. Interfaces should contains at least a method or a constant, and not be totally empty.
<?php
// an empty interface
interface empty {}
// an normal interface
interface normal {
public function i() ;
}
// a constants interface
interface constantsOnly {
const FOO = 1;
}
?>
See also Empty interfaces are bad practice and Blog : Are empty interfaces code smell?.
1.2.643.1. Suggestions¶
Remove the interface
Add some methods or constants to the interface
1.2.643.2. Specs¶
Short name |
Interfaces/EmptyInterface |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.644. Interface Methods¶
List the names of the methods in an interface.
<?php
interface i {
// This is an interface method name
function foo() ;
}
?>
1.2.644.1. Specs¶
Short name |
Interfaces/InterfaceMethod |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.645. Interfaces Usage¶
List of used interfaces.
Interfaces are used when mentioned in a class or another interface, with implements keyword; they are used in instanceof expression, in typehints and class constant.
<?php
// interface definition
interface i {
const I = 2;
}
// interface extension
interface i2 extends i {}
// interface implementation
class foo implements i {}
$foo = new foo();
var_dump($foo instanceof i);
function bar( i $arg) { }
bar($foo);
// in class constant
echo i::I;
?>
1.2.645.1. Specs¶
Short name |
Interfaces/InterfaceUsage |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.646. Interfaces Glossary¶
List of all the defined interfaces in the code.
<?php
// interfaceName is reported
interface interfaceName {
function interfaceMethod() ;
}
?>
1.2.646.1. Specs¶
Short name |
Interfaces/Interfacenames |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.647. Is An Extension Interface¶
This is an interface defined in a PHP C extension.
<?php
// MyInterface is not recognized as an extension interface
function foo ( MyInterface $a) {
// \ArrayAccess is recognized as a native PHP extension
if ($a instanceof \ArrayAccess) {
// doSomething()
}
}
?>
1.2.647.1. Specs¶
Short name |
Interfaces/IsExtInterface |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.648. Interfaces Is Not Implemented¶
Classes that implements interfaces, must implements each of the interface’s methods.
<?php
class x implements i {
// This method implements the foo method from the i interface
function foo() {}
// The method bar is missing, yet is requested by interface i
function foo() {}
}
interface i {
function foo();
function bar();
}
?>
This problem tends to occur in code that splits interfaces and classes by file. This means that PHP’s linting will skip the definitions and not find the problem. At execution time, the definitions will be checked, and a Fatal error will occur.
This situation usually detects code that was forgotten during a refactorisation of the interface or the class and its sibblings.
See also Interfaces.
1.2.648.1. Suggestions¶
Implements all the methods from the interfaces
Remove the class
Make the class abstract
Make the missing methods abstract
1.2.648.2. Specs¶
Short name |
Interfaces/IsNotImplemented |
Rulesets |
|
Exakat since |
1.9.5 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.649. Interfaces Don’t Ensure Properties¶
When using an interface as a typehint, properties are not enforced, nor available.
An interface is a template for a class, which specify the minimum amount of methods and constants. Properties are never defined in an interface, and should not be relied upon.
<?php
interface i {
function m () ;
}
class x implements i {
public $p = 1;
function m() {
return $this->p;
}
}
function foo(i $i, x $x) {
// this is invalid, as $p is not defined in i, so it may be not available
echo $i->p;
// this is valid, as $p is defined in $x
echo $x->p;
}
?>
1.2.649.1. Suggestions¶
Use classes for typehint when properties are accessed
Only use methods and constants which are available in the interface
1.2.649.2. Specs¶
Short name |
Interfaces/NoGaranteeForPropertyConstant |
Rulesets |
|
Exakat since |
1.9.5 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.650. PHP Interfaces¶
List of PHP interfaces being used in the code.
<?php
// Countable is a PHP native interface
class Enumeration extends Countable {
function count() { return 1; }
}
?>
1.2.650.1. Specs¶
Short name |
Interfaces/Php |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.651. Possible Interfaces¶
This analyzer lists classes that may be a base to create interfaces.
Currently, classes with more than 1 defined method are used to identify possible interfaces. An interfaces are considered when at least 2 methods are common in 3 classes.
Only the name of the method is used to identify possible methodes. Signature and method options are not taken into account.
<?php
class a {
function m1 () {}
function m2 () {}
function m3 () {}
}
class b {
function m1 () {}
function m2 () {}
function m4 () {}
}
// This class has not enough shared methods with other classes
class c {
function m1 () {}
function m4 () {}
function m5 () {}
}
?>
1.2.651.1. Suggestions¶
Add those interfaces, and use the implements keyword in the mentionned classes.
See also and .
1.2.651.2. Specs¶
Short name |
Interfaces/PossibleInterfaces |
Rulesets |
|
Exakat since |
2.0.6 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Medium |
Available in |
1.2.652. Repeated Interface¶
A class should implements only once an interface. An interface can only extends once another interface. In both cases, parent classes or interfaces must be checked.
PHP accepts multiple times the same interface in the implements clause. In fact, it doesn’t do anything beyond the first implement.
<?php
use i as j;
interface i {}
// Multiple ways to reference an interface
class foo implements i, \i, j {}
// This applies to interfaces too
interface bar extends i, \i, j {}
?>
This code may compile, but won’t execute.
See also Object Interfaces and The Basics.
1.2.652.1. Suggestions¶
Remove the interface usage at the lowest class or interface
1.2.652.2. Specs¶
Short name |
Interfaces/RepeatedInterface |
Rulesets |
|
Exakat since |
1.4.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.653. Undefined Interfaces¶
Some typehints or
instanceofthat are relying on undefined interfaces or classes. They will always return false. Any condition based upon them are dead code.
<?php
class var implements undefinedInterface {
// If undefinedInterface is undefined, this code lints but doesn't run
}
if ($o instanceof undefinedInterface) {
// This is silent dead code
}
function foo(undefinedInterface $a) {
// This is dead code
// it will probably be discovered at execution
}
?>
1.2.653.1. Suggestions¶
Implement the missing interfaces
Remove the code governed by the missing interface : the whole method if it is an typehint, the whole if/then if it is a condition.
See also Object interfaces, Type declarations and Instanceof.
1.2.653.2. Specs¶
Short name |
Interfaces/UndefinedInterfaces |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.654. Unused Interfaces¶
Those interfaces are defined and never used. They should be removed, as they are dead code.
Interfaces may be use as parent for other interfaces, as typehint (argument, return and property), in instance of.
<?php
interface used {}
interface unused {}
// Used by implementation
class c implements used {}
// Used by extension
interface j implements used {}
$x = new c;
// Used in a instanceof
var_dump($x instanceof used);
// Used in a typehint
function foo(Used $x) {}
?>
1.2.654.1. Suggestions¶
Remove the interface
Actually use the interface
1.2.654.2. Specs¶
Short name |
Interfaces/UnusedInterfaces |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.655. Used Interfaces¶
Interfaces used in the code.
<?php
interface used {}
// Used by implementation
class c implements used {}
// Used by extension
interface j implements used {}
$x = new c;
// Used in a instanceof
var_dump($x instanceof used);
// Used in a typehint
function foo(Used $x) {}
?>
1.2.655.1. Specs¶
Short name |
Interfaces/UsedInterfaces |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.656. Useless Interfaces¶
The interfaces below are defined and are implemented by some classes.
However, they are never used to enforce an object’s class in the code, using instanceof or in a typehint. As they are currently used, those interfaces may be removed without change in behavior.
<?php
// only defined interface but never enforced
interface i {};
class c implements i {}
?>
Interfaces should be used in Typehint or with the instanceof operator.
<?php
interface i {};
function foo(i $arg) {
// Now, $arg is always an 'i'
}
function bar($arg) {
if (!($arg instanceof i)) {
// Now, $arg is always an 'i'
}
}
?>
1.2.656.1. Suggestions¶
Use the interface with instanceof, or a typehint
Drop the interface altogether : both definition and implements keyword
1.2.656.2. Specs¶
Short name |
Interfaces/UselessInterfaces |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
ClearPHP |
|
Examples |
|
Available in |
1.2.657. Aliases¶
List of all aliases used, to alias namespaces.
<?php
// This is an alias
use stdClass as aClass;
// This is not an alias : it is not explicit
use stdClass;
trait t {
// This is not an alias, it's a trait usage
use otherTrait;
}
?>
See also Using namespaces: Aliasing/Importing.
1.2.657.1. Specs¶
Short name |
Namespaces/Alias |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.658. Possible Alias Confusion¶
An alias is used for a class that doesn’t belong to the current namespace, while there is such a class. This also applies to traits and interfaces.
When no alias is used, PHP will search for a class in the local space. Since classes, traits and interfaces are usually stored one per file, it is a valid syntax to create an alias, even if this alias name is the name of a class in the same namespace.
Yet, with an alias refering to a remote class, while a local one is available, it is possible to generate confusion.
<?php
// This should be in a separate file, but has been merged here, for display purposes.
namespace A {
//an alias from a namespace called C
use C\A as C_A;
//an alias from a namespace called C, which will superseed the local A\B class (see below)
use C\D as B;
}
namespace A {
// There is a class B in the A namespace
class B {}
}
?>
1.2.658.1. Suggestions¶
Avoid using existing classes names for alias
Use a coding convention to distinguish alias from names
1.2.658.2. Specs¶
Short name |
Namespaces/AliasConfusion |
Rulesets |
|
Exakat since |
2.1.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.659. Fully Qualified Constants¶
Constants defined with their namespace.
When defining constants with define() function, it is possible to include the actual namespace :
<?php
define('a\b\c', 1);
?>
However, the name should be fully qualified without the initial . Here, abc constant will never be accessible as a namespace constant, though it will be accessible via the constant() function.
Also, the namespace will be absolute, and not a relative namespace of the current one.
1.2.659.1. Suggestions¶
Drop the initial when creating constants with define() : for example, use trim($x, ‘'), which removes anti-slashes before and after.
1.2.659.2. Specs¶
Short name |
Namespaces/ConstantFullyQualified |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.660. Could Use Alias¶
This long name may be reduced by using an available alias.
This applies to classes (as full name or prefix), and to constants and functions.
<?php
use a\b\c;
use function a\b\c\foo;
use const a\b\c\D;
// This may be reduced with the above alias to c\d()
new a\b\c\d();
// This may be reduced to c\d\e\f
new a\b\c\d\e\f();
// This may be reduced to c()
new a\b\c();
// This may be reduced to D
echo a\b\c\D;
// This may be reduced to D
a\b\c\foo();
// This can't be reduced : it is an absolute name
\a\b\c\foo();
// This can't be reduced : it is no an alias nor a prefix
a\b\d\foo();
?>
See also Using namespaces: Aliasing/Importing ¶.
1.2.660.1. Suggestions¶
Use all your aliases so as to make the code shorter and more readable
Add new aliases for missing path
Make class names absolute and drop the aliases
1.2.660.2. Specs¶
Short name |
Namespaces/CouldUseAlias |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.661. Empty Namespace¶
Declaring a namespace in the code and not using it for structure declarations or global instructions is useless.
Using simple style :
<?php
namespace Y;
class foo {}
namespace X;
// This is useless
?>
Using bracket-style syntax :
<?php
namespace X {
// This is useless
}
namespace Y {
class foo {}
}
?>
1.2.661.1. Suggestions¶
Remove the namespace
1.2.661.2. Specs¶
Short name |
Namespaces/EmptyNamespace |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
ClearPHP |
|
Available in |
1.2.662. Global Import¶
Mark a Use statement that is importing a global class in the current file.
<?php
namespace Foo {
// This is a global import
use Stdclass;
}
?>
1.2.662.1. Specs¶
Short name |
Namespaces/GlobalImport |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.664. Multiple Alias Definitions Per File¶
Avoid aliasing the same name with different aliases. This leads to confusion.
<?php
// first occurrence
use name\space\ClasseName;
// when this happens, several other uses are mentionned
// name\space\ClasseName has now two names
use name\space\ClasseName as anotherName;
?>
See also Namespaces/MultipleAliasDefinition.
1.2.664.1. Specs¶
Short name |
Namespaces/MultipleAliasDefinitionPerFile |
Rulesets |
|
Exakat since |
0.10.3 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.665. Multiple Alias Definitions¶
Some aliases are representing different classes across the repository. This leads to potential confusion.
Across an application, it is recommended to use the same namespace for one alias. Failing to do this lead to the same keyword to represent different values in different files, with different behavior. Those are hard to find bugs.
<?php
namespace A {
use d\d; // aka D
}
// Those are usually in different files, rather than just different namespaces.
namespace B {
use b\c as D; // also D. This could be named something else
}
?>
1.2.665.1. Suggestions¶
Give more specific names to classes
Use an alias ‘use AB ac BC’ to give locally another name
1.2.665.2. Specs¶
Short name |
Namespaces/MultipleAliasDefinitions |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.666. Namespaces¶
Inventory of all namespaces.
1.2.666.1. Specs¶
Short name |
Namespaces/NamespaceUsage |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.667. Namespaces Glossary¶
List of all the defined namespaces in the code, using the namespace keyword.
<?php
// One reported namespace
namespace one\name\space {}
// This global namespace is reported, as it is explicit
namespace { }
?>
Global namespaces are mentioned when they are explicitly used.
1.2.667.1. Specs¶
Short name |
Namespaces/Namespacesnames |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.668. Should Make Alias¶
Long names should be aliased.
Aliased names are easy to read at the beginning of the script; they may be changed at one point, and update the whole code at the same time. Finally, short names makes the rest of the code readable.
<?php
namespace x\y\z;
use a\b\c\d\e\f\g as Object;
// long name, difficult to read, prone to change.
new a\b\c\d\e\f\g();
// long name, difficult to read, prone to silent dead code if namespace change.
if ($o instanceof a\b\c\d\e\f\g) {
}
// short names Easy to update all at once.
new Object();
if ($o instanceof Object) {
}
?>
1.2.668.1. Specs¶
Short name |
Namespaces/ShouldMakeAlias |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.669. Unresolved Use¶
The following use instructions cannot be resolved to a known class, interface, trait, constant or function. They should be dropped or fixed.
A known class, interface, trait, constant or function is defined in PHP (standard), an extension, a stub or the current code.
<?php
namespace A {
// class B is defined
class B {}
// class C is not defined
}
namespace X/Y {
use A/B; // This use is valid
use A/C; // This use point to nothing.
new B();
new C();
}
?>
Use expression are options for the current namespace.
1.2.669.1. Suggestions¶
Remove the use expression
Fix the use expression
See also and Using namespaces: Aliasing/Importing.
1.2.669.2. Specs¶
Short name |
Namespaces/UnresolvedUse |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
ClearPHP |
|
Available in |
1.2.670. Unused Use¶
Unused use statements. They may be removed, as they clutter the code and slows PHP by forcing it to search in this list for nothing.
<?php
use A as B; // Used in a new call.
use Unused; // Never used. May be removed
$a = new B();
?>
1.2.670.1. Suggestions¶
Remove the unused use
1.2.670.2. Specs¶
Short name |
Namespaces/UnusedUse |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Instant (5 mins) |
Precision |
Very high |
ClearPHP |
|
Available in |
1.2.671. Use Const And Functions¶
Since PHP 5.6 it is possible to import specific functions or constants from other namespaces.
<?php
namespace A {
const X = 1;
function foo() { echo __FUNCTION__; }
}
namespace My{
use function A\foo;
use constant A\X;
echo foo(X);
}
?>
See also Using namespaces: Aliasing/Importing.
1.2.671.1. Specs¶
Short name |
Namespaces/UseFunctionsConstants |
Rulesets |
CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, All |
Exakat since |
0.8.4 |
PHP Version |
5.6+ |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
Very high |
Available in |
1.2.672. Use With Fully Qualified Name¶
Use statement doesn’t require a fully qualified name.
PHP manual recommends not to use fully qualified name (starting with ) when using the ‘use’ statement : they are “the leading backslash is unnecessary and not recommended, as import names must be fully qualified, and are not processed relative to the current namespace”.
<?php
// Recommended way to write a use statement.
use A\B\C\D as E;
// No need to use the initial \
use \A\B\C\D as F;
?>
1.2.672.1. Suggestions¶
Remove the initial in use expressions.
1.2.672.2. Specs¶
Short name |
Namespaces/UseWithFullyQualifiedNS |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.673. Used Use¶
List of use statements. Those use are made to import namespaces structures, not to include traits.
<?php
namespace A {
class b {}
}
namespace B {
use A\B as B;
new B();
}
?>
See also Using namespaces: Aliasing/Importing.
1.2.673.1. Specs¶
Short name |
Namespaces/UsedUse |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.674. Wrong Case Namespaces¶
Namespaces are case-insentives.
<?php
// Namespaces should share the same case
namespace X {}
namespace x {}
?>
1.2.674.1. Suggestions¶
Synchronize all names
1.2.674.2. Specs¶
Short name |
Namespaces/WrongCase |
Rulesets |
|
Exakat since |
1.9.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.675. Abstract Away¶
Avoid using PHP native functions that produce data direcly in the code. For example, date() or random_int(). They should be abstracted away in a method, that will be replaced later for testing purposes, or even debugging.
To abstract such calls, place them in a method, and add an interface to this method. Then, create and use those objects.
<?php
// abstracted away date
$today = new MyDate();
echo 'Date : '.$today->date('r');
// hard coded date of today : it changes all the time.
echo 'Date : '.date('r');
interface MyCalendar{
function date($format) : string ;
}
class MyDate implements MyCalendar {
function date($format) : string { return date('r'); }
}
// Valid implementation, reserved for testing purpose
// This prevents from waiting 4 years for a test.
class MyDateForTest implements MyCalendar {
function date($format) : string { return date('r', strtotime('2016-02-29 12:00:00')); }
}
?>
This analysis targets two API for abstraction : time and random values. Time and date related functions may be replaced by Carbon, Clock, Chronos. Random values may be replaced with RandomLib or a custome interface.
See also Being in control of time in PHP and How to test non-deterministic code.
1.2.675.1. Suggestions¶
Abstract away the calls to native PHP functions, and upgrade the unit tests
Name |
Default |
Type |
Description |
abstractableCalls |
ini_hash |
Functions that shouldn’t be called directly, unless in a method. |
|
abstractableClasses |
ini_hash |
Classes that shouldn’t be instantiated directly, unless in a method. |
1.2.675.2. Specs¶
Short name |
Patterns/AbstractAway |
Rulesets |
|
Exakat since |
2.1.5 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Medium |
Available in |
1.2.676. Courier Anti-Pattern¶
The courier anti-pattern is the storage of a dependency by a class, in order to create an instance that requires this dependency.
The class itself doesn’t actually need this dependency, but has a dependency to a class that requires it.
<?php
// The foo class requires bar
class Foo {
public function __construct(Bar $b) {
}
}
// Class A doesn't depends on Bar, but depends on Foo
// Class A never uses Bar, but only uses Foo.
class A {
private $courier;
public function __construct(Bar $courier) {
$this->courier = $courier;
}
public function Afoo() {
$b = new Foo($this->courier);
}
}
?>
The alternative here is to inject Foo instead of Bar.
See also Courier Anti-pattern.
1.2.676.1. Specs¶
Short name |
Patterns/CourrierAntiPattern |
Rulesets |
|
Exakat since |
0.11.6 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.677. Dependency Injection¶
A dependency injection is a typehinted argument, that is stored in a property by the constructor.
<?php
// Classic dependency injection
class foo {
private $bar;
public function __construct(Bar $bar) {
$this->bar = $bar;
}
public function doSomething($args) {
return $this->bar->barbar($args);
}
}
// Without typehint, this is not a dependency injection
class foo {
private $bar;
public function __construct($bar) {
$this->bar = $bar;
}
}
?>
See also Understanding Dependency Injection.
1.2.677.1. Specs¶
Short name |
Patterns/DependencyInjection |
Rulesets |
|
Exakat since |
0.11.6 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.678. An OOP Factory¶
A method or function that implements a factory. A factory is a class that handles the creation of an object, based on parameters. The factory hides the logic that leads to the creation of the object.
<?php
class AutomobileFactory {
public static function create($make, $model) {
$className = \\Automaker\\Brand\\$make;
return new $className($model);
}
}
// The factory is able to build any car, based on their
$fuego = AutomobileFactory::create('Renault', 'Fuego');
print_r($fuego->getMakeAndModel()); // outputs Renault Fuego
?>
See also Factory (object-oriented programming) and Factory.
1.2.678.1. Specs¶
Short name |
Patterns/Factory |
Rulesets |
|
Exakat since |
1.6.7 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.679. array_key_exists() Speedup¶
isset() used to be the fastest, but array_key_exists() is. Since PHP 7.4, array_key_exists() has its own opcode, leading to better features and speed.
isset() is faster for all non-empty values, but is limited when the value is NULL or empty : then, array_key_exists() has the good features.
This change makes `array_key_exists() <https://www.php.net/array_key_exists>`_ actually faster than `isset() <https://www.www.php.net/isset>`_ by ~25% (tested with GCC 8, -O3, march=native, mtune=native)..
<?php
$foo = [123 => 456];
// This is sufficient and efficient since PHP 7.4
if (array_search_key($foo[123])) {
// do something
}
// taking advantages of performances for PHP 7.4 and older
if (isset($foo[123]) || array_search_key($foo[123])) {
// do something
}
?>
See also Implement ZEND_ARRAY_KEY_EXISTS opcode to speed up `array_key_exists() <https://github.com/php/php-src/pull/3360>`_.
1.2.679.1. Suggestions¶
Remove the logical test and the isset() call
1.2.679.2. Specs¶
Short name |
Performances/ArrayKeyExistsSpeedup |
Rulesets |
|
Exakat since |
1.6.1 |
PHP Version |
7.4+ |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.680. No array_merge() In Loops¶
array_merge() is memory intensive : every call will duplicate the arguments in memory, before merging them.
To handle arrays that may be quite big, it is recommended to avoid using array_merge() in a loop. Instead, one should use array_merge() with as many arguments as possible, making the merge a on time call.
<?php
// A large multidimensional array
$source = ['a' => ['a', 'b', /*...*/],
'b' => ['b', 'c', 'd', /*...*/],
/*...*/
];
// Faster way
$b = array();
foreach($source as $key => $values) {
//Collect in an array
$b[] = $values;
}
// One call to array_merge
$b = call_user_func_array('array_merge', $b);
// or with variadic
$b = call_user_func('array_merge', ..$b);
// Fastest way (with above example, without checking nor data pulling)
$b = call_user_func_array('array_merge', array_values($source))
// or
$b = call_user_func('array_merge', ...array_values($source))
// Slow way to merge it all
$b = array();
foreach($source as $key => $values) {
$b = array_merge($b, $values);
}
?>
Note that array_merge_recursive() and file_put_contents() are affected and reported the same way.
1.2.680.1. Suggestions¶
Store all intermediate arrays in a temporary variable, and use array_merge() once, with ellipsis or call_user_func_array().
1.2.680.2. Specs¶
Short name |
Performances/ArrayMergeInLoops |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
ClearPHP |
|
Examples |
|
Available in |
1.2.681. Autoappend¶
Appending a variable to itself leads to enormous usage of memory.
<?php
// Always append a value to a distinct variable
foreach($a as $b) {
$c[] = $b;
}
// This copies the array to itself, and double the size each loop
foreach($a as $b) {
$c[] = $c;
}
?>
1.2.681.1. Suggestions¶
Change the variable in the append, on the left
Change the variable in the append, on the right
1.2.681.2. Specs¶
Short name |
Performances/Autoappend |
Rulesets |
|
Exakat since |
1.8.3 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.682. Avoid array_push()¶
array_push() is slower than the [] operator.
This is also true if the [] operator is called several times, while array_push() may be called only once. And using count after the push is also faster than collecting array_push() return value.
<?php
$a = [1,2,3];
// Fast version
$a[] = 4;
$a[] = 5;
$a[] = 6;
$a[] = 7;
$count = count($a);
// Slow version
array_push($a, 4);
$count = array_push($a, 5,6,7);
// Multiple version :
$a[] = 1;
$a[] = 2;
$a[] = 3;
array_push($a, 1, 2, 3);
?>
This is a micro-optimisation.
1.2.682.1. Suggestions¶
Use the [] operator
1.2.682.2. Specs¶
Short name |
Performances/AvoidArrayPush |
Rulesets |
|
Exakat since |
0.9.1 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.683. Cache Variable Outside Loop¶
Avoid recalculating constant values inside the loop.
Do the calculation once, outside the loops, and then reuse the value each time.
One of the classic example if doing count($array) in a for loop : since the source is constant during the loop, the result of count() is always the same.
<?php
$path = '/some/path';
$fullpath = realpath("$path/more/dirs/");
foreach($files as $file) {
// Only moving parts are used in the loop
copy($file, $fullpath.$file);
}
$path = '/some/path';
foreach($files as $file) {
// $fullpath is calculated each loop
$fullpath = realpath("$path/more/dirs/");
copy($file, $fullpath.$file);
}
?>
Depending on the load of the called method, this may increase the speed of the loop from little to enormously.
1.2.683.1. Suggestions¶
Avoid using blind variables outside loops.
Store blind variables in local variables or properties for later reuse.
1.2.683.2. Specs¶
Short name |
Performances/CacheVariableOutsideLoop |
Rulesets |
|
Exakat since |
1.2.8 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.684. fputcsv() In Loops¶
fputcsv() is slow when called on each row. It actually flushes the data to the disk each time, and that results in a inefficient dump to the disk, each call.
To speed up this process, it is recommended to dump the csv to memory first, then dump the memory to the disk, in larger chunks. Since fputcsv() works only on stream, it is necessary to use a memory stream.
<?php
// Speedy yet memory intensive version
$f = fopen('php://memory', 'w+');
foreach($data_source as $row) {
// You may configure fputcsv as usual
fputcsv($f, $row);
}
rewind($f); // Important
$fp = fopen('final.csv', 'w+');
fputs($fp, stream_get_contents($f));
fclose($fp);
fclose($f);
// Slower version
$fp = fopen('final.csv', 'w+');
foreach($data_source as $row) {
// You may configure fputcsv as usual
fputcsv($fp, $row);
}
fclose($fp);
?>
The speed improvement is significant on small rows, while it may be less significant on larger rows : with more data in the rows, the file buffer may fill up more efficiently. On small rows, the speed gain is up to 7 times.
1.2.684.1. Suggestions¶
Use fputcsv() on a memory stream, and flush it on the disk once
1.2.684.2. Specs¶
Short name |
Performances/CsvInLoops |
Rulesets |
|
Exakat since |
1.5.5 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.685. Do In Base¶
Use SQL expression to compute aggregates.
<?php
// Efficient way
$res = $db->query('SELECT sum(e) AS sumE FROM table WHERE condition');
// The sum is already done
$row = $res->fetchArray();
$c += $row['sumE'];
// Slow way
$res = $db->query('SELECT e FROM table WHERE condition');
// This aggregates the column e in a slow way
while($row = $res->fetchArray()) {
$c += $row['e'];
}
?>
1.2.685.1. Suggestions¶
Rework the query to move the calculations in the database
1.2.685.2. Specs¶
Short name |
Performances/DoInBase |
Rulesets |
|
Exakat since |
1.2.8 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.686. Double array_flip()¶
Avoid double array_flip() to gain speed. While array_flip() alone is usually useful, a double call to array_flip() is made to make values and keys unique.
<?php
// without array_flip
function foo($array, $value) {
$key = array_search($array, $value);
if ($key !== false) {
unset($array[$key]);
}
return $array;
}
// double array_flip
// array_flip() usage means that $array's values are all unique
function foo($array, $value) {
$flipped = array_flip($value);
unset($flipped[$value]);
return array_flip($flipped);
}
?>
1.2.686.1. Suggestions¶
use array_unique() or array_count_values
use array_flip() once, and let PHP garbage collect it later
Keep the original values in a separate variable
1.2.686.2. Specs¶
Short name |
Performances/DoubleArrayFlip |
Rulesets |
|
Exakat since |
1.1.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.687. Fetch One Row Format¶
When reading results with ext/Sqlite3, it is recommended to explicitly request SQLITE3_NUM or SQLITE3_ASSOC, while avoiding the default value and SQLITE3_BOTH.
<?php
$res = $database->query($query);
// Fastest version, but less readable
$row = $res->fetchArray(\SQLITE3_NUM);
// Almost the fastest version, and more readable
$row = $res->fetchArray(\SQLITE3_ASSOC);
// Default version. Quite slow
$row = $res->fetchArray();
// Worse case
$row = $res->fetchArray(\SQLITE3_BOTH);
?>
This is a micro-optimisation. The difference may be visible with 200k rows fetches, and measurable with 10k.
1.2.687.1. Suggestions¶
Specify the result format when reading rows from a Sqlite3 database
1.2.687.2. Specs¶
Short name |
Performances/FetchOneRowFormat |
Rulesets |
|
Exakat since |
0.9.6 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.688. Isset() On The Whole Array¶
Isset() works quietly on a whole array. There is no need to test all previous index before testing for the target index.
<?php
// Straight to the point
if (isset($a[1]['source'])) {
// Do something with $a[1]['source']
}
// Doing too much work
if (isset($a) && isset($a[1]) && isset($a[1]['source'])) {
// Do something with $a[1]['source']
}
?>
There is a gain in readability, by avoiding long and hard to read logical expression, and reducing them in one simple isset call.
There is a gain in performances by using one call to isset, instead of several, but it is a micro-optimization.
See also Isset <http://www.php.net/`isset>`_.
1.2.688.1. Suggestions¶
Remove all unnecessary calls to isset()
1.2.688.2. Specs¶
Short name |
Performances/IssetWholeArray |
Rulesets |
|
Exakat since |
1.5.6 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.689. Joining file()¶
Use file() to read lines separately.
Applying join(‘’, ) or implode(‘’, ) to the result of file() provides the same results than using file_get_contents(), but at a higher cost of memory and processing.
If the delimiter is not ‘’, then implode() and file() are a better solution than file_get_contents() and str_replace() or nl2br().
<?php
// memory intensive
$content = file_get_contents('path/to/file.txt');
// memory and CPU intensive
$content = join('', file('path/to/file.txt'));
// Consider reading the data line by line and processing it along the way,
// to save memory
$fp = fopen('path/to/file.txt', 'r');
while($line = fget($fp)) {
// process a line
}
fclose($fp);
?>
Always use file_get_contents() to get the content of a file as a string. Consider using readfile() to echo the content directly to the output.
See also file_get_contents and file.
1.2.689.1. Suggestions¶
Use file_get_contents() instead of implode(file()) to read the whole file at once.
Use readfile() to echo the content to stdout at once.
Use fopen() to read the lines one by one, generator style.
1.2.689.2. Specs¶
Short name |
Performances/JoinFile |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.690. Logical To in_array¶
Multiples exclusive comparisons may be replaced by in_array().
in_array() makes the alternatives more readable, especially when the number of alternatives is large. In fact, the list of alternative may even be set in a variable, and centralized for easier management.
Even two ‘or’ comparisons are slower than using a in_array() call. More calls are even slower than just two. This is a micro-optimisation : speed gain is low, and marginal. Code centralisation is a more significant advantage.
<?php
// Set the list of alternative in a variable, property or constant.
$valid_values = array(1, 2, 3, 4);
if (in_array($a, $valid_values) ) {
// doSomething()
}
if ($a == 1 || $a == 2 || $a == 3 || $a == 4) {
// doSomething()
}
// in_array also works with strict comparisons
if (in_array($a, $valid_values, true) ) {
// doSomething()
}
if ($a === 1 || $a === 2 || $a === 3 || $a === 4) {
// doSomething()
}
?>
See also in_array().
1.2.690.1. Suggestions¶
Replace the list of comparisons with a in_array() call on an array filled with the various values
Replace the list of comparisons with a isset() call on a hash whose keys are the various values
1.2.690.2. Specs¶
Short name |
Performances/LogicalToInArray |
Rulesets |
|
Exakat since |
0.12.5 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Examples |
|
Available in |
1.2.691. Make One Call With Array¶
Avoid calling the same function several times by batching the calls with arrays.
Calling the same function to chain modifications tends to be slower than calling the same function with all the transformations at the same time. Some PHP functions accept scalars or arrays, and using the later is more efficient.
<?php
$string = 'abcdef';
//str_replace() accepts arrays as arguments
$string = str_replace( ['a', 'b', 'c'],
['A', 'B', 'C'],
$string);
// Too many calls to str_replace
$string = str_replace( 'a', 'A', $string);
$string = str_replace( 'b', 'B', $string);
$string = str_replace( 'c', 'C', $string);
// Too many nested calls to str_replace
$string = str_replace( 'a', 'A', str_replace( 'b', 'B', str_replace( 'c', 'C', $string)));
?>
Potential replacements :
Function |
Replacement |
str_replace() str_ireplace() substr_replace() preg_replace() preg_replace_callback() |
str_replace() str_replace() substr_replace() preg_replace() preg_replace_callback_array() |
<?php
$subject = 'Aaaaaa Bbb';
//preg_replace_callback_array() is better than multiple preg_replace_callback :
preg_replace_callback_array(
[
'~[a]+~i' => function ($match) {
echo strlen($match[0]), ' matches for a found', PHP_EOL;
},
'~[b]+~i' => function ($match) {
echo strlen($match[0]), ' matches for b found', PHP_EOL;
}
],
$subject
);
$result = preg_replace_callback('~[a]+~i', function ($match) {
echo strlen($match[0]), ' matches for a found', PHP_EOL;
}, $subject);
$result = preg_replace_callback('~[b]+~i', function ($match) {
echo strlen($match[0]), ' matches for b found', PHP_EOL;
}, $subject);
//str_replace() accepts arrays as arguments
$string = str_replace( ['a', 'b', 'c'],
['A', 'B', 'C'],
$string);
// Too many calls to str_replace
$string = str_replace( 'a', 'A');
$string = str_replace( 'b', 'B');
$string = str_replace( 'c', 'C');
?>
1.2.691.1. Suggestions¶
use str_replace() with arrays as arguments.
use preg_replace() with arrays as arguments.
use preg_replace_callback() for merging multiple complex calls.
1.2.691.2. Specs¶
Short name |
Performances/MakeOneCall |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.692. No mb_substr In Loop¶
Do not use loops on mb_substr().
mb_substr() always starts at the beginning of the string ot search for the nth char, and recalculate everything. This means that the first iterations are as fast as substr() (for comparison), while the longer the string, the slower mb_substr().
The recommendation is to use preg_split() with the u option, to split the string into an array. This save multiple recalculations.
<?php
// Split the string by characters
$array = preg_split('//u', $string, -1, PREG_SPLIT_NO_EMPTY);
foreach($array as $c) {
doSomething($c);
}
// Slow version
$nb = mb_strlen($mb);
for($i = 0; $i < $nb; ++$i) {
// Fetch a character
$c = mb_substr($string, $i, 1);
doSomething($c);
}
?>
See also Optimization: How I made my PHP code run 100 times faster and How to iterate UTF-8 string in PHP?.
1.2.692.1. Suggestions¶
Use preg_split() and loop on its results.
1.2.692.2. Specs¶
Short name |
Performances/MbStringInLoop |
Rulesets |
|
Exakat since |
1.9.6 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.693. Memoize MagicCall¶
Cache calls to magic methods in local variable. Local cache is faster than calling again the magic method as soon as the second call, provided that the value hasn’t changed.
__get is slower, as it turns a simple member access into a full method call.
<?php
class x {
private $values = array();
function __get($name) {
return $this->values[$name];
}
// more code to set values to this class
}
function foo(x $b) {
$a = $b->a;
$c = $b->c;
$d = $c; // using local cache, no new access to $b->__get($name)
$e = $b->a; // Second access to $b->a, through __get
}
function bar(x $b) {
$a = $b->a;
$c = $b->c;
$b->bar2(); // this changes $b->a and $b->c, but we don't see it
$d = $b->c;
$e = $b->a; // Second access to $b->a, through __get
}
?>
The caching is not possible if the processing of the object changes the value of the property.
See also __get performance questions with PHP, Make Magic Concrete and Benchmarking magic.
1.2.693.1. Suggestions¶
Cache the value in a local variable, and reuse that variable
Make the property concrete in the class, so as to avoid __get() altogether
Name |
Default |
Type |
Description |
minMagicCallsToGet |
2 |
integer |
Minimal number of calls of a magic property to make it worth locally caching. |
1.2.693.2. Specs¶
Short name |
Performances/MemoizeMagicCall |
Rulesets |
|
Exakat since |
1.8.3 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.694. Avoid Concat In Loop¶
Concatenations inside a loop generate a lot of temporary variables. They are accumulated and tend to raise the memory usage, leading to slower performances.
It is recommended to store the values in an array, and then use implode() on that array to make the concatenation at once. The effect is positive when the source array has at least 50 elements.
<?php
// Concatenation in one operation
$tmp = array();
foreach(data_source() as $data) {
$tmp[] = $data;
}
$final = implode('', $tmp);
// Concatenation in many operations
foreach(data_source() as $data) {
$final .= $data;
}
?>
The same doesn’t apply to addition and multiplication, with array_sum() and array_multiply(), as those operations work on the current memory allocation, and don’t need to allocate new memory at each step.
See also PHP 7 performance improvements (3/5): Encapsed strings optimization.
1.2.694.1. Suggestions¶
Collect all pieces in an array, then implode() the array in one call.
1.2.694.2. Specs¶
Short name |
Performances/NoConcatInLoop |
Rulesets |
|
Exakat since |
0.12.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Examples |
|
Available in |
1.2.695. Avoid glob() Usage¶
Besides, whenever possible, use scandir() instead of glob().
<?php
// Scandir without sorting is the fastest.
scandir('docs/', SCANDIR_SORT_NONE);
// Scandir sorts files by default. Same as above, but with sorting
scandir('docs/');
// glob sorts files by default. Same as below, but no sorting
glob('docs/*', GLOB_NOSORT);
// glob sorts files by default. This is the slowest version
glob('docs/*');
?>
Using opendir() and a while loop may be even faster.
This analysis skips scandir() and glob() if they are expliciely configured with flags (aka, sorting is explicitly needed).
glob() accepts wildchar, such as *, that may not easily replaced with scandir() or opendir().
See also Putting glob to the test, How to list files recursively in a directory with PHP iterators and glob://.
1.2.695.1. Suggestions¶
Use FilesystemIterator, DirectoryIterator classes.
Use
RegexIteratorto filter any unwanted results fromFilesystemIterator.Use
globprotocol for files : $it = new DirectoryIterator(‘glob://path/to/examples/*.php’);
1.2.695.2. Specs¶
Short name |
Performances/NoGlob |
Rulesets |
|
Exakat since |
0.9.6 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.696. No Count With 0¶
Comparing count(), strlen() or mb_strlen() to 0 is a waste of resources. There are three distinct situations.
When comparing count() with 0, with ===, ==, !==, !=, it is more efficient to use empty(). empty() is a language construct that checks if a value is present, while count() actually load the number of element.
<?php
// Checking if an array is empty
if (count($array) == 0) {
// doSomething();
}
// This may be replaced with
if (empty($array)) {
// doSomething();
}
?>
When comparing count() strictly with 0 and >, it is more efficient to use !(empty( ))
<?php
// Checking if an array is empty
if (count($array) > 0) {
// doSomething();
}
// This may be replaced with
if (!empty($array)) {
// doSomething();
}
Of course comparing count() with negative values, or with >= is useless.
<?php
// Checking if an array is empty
if (count($array) < 0) {
// This never happens
// doSomething();
}
?>
Comparing count(), strlen() or mb_strlen() with other values than 0 cannot be replaced with a comparison with empty().
Note that this is a micro-optimisation : since PHP keeps track of the number of elements in arrays (or number of chars in strings), the total computing time of both operations is often lower than a ms. However, both functions tends to be heavily used, and may even be used inside loops.
See also count, strlen and mb_strlen.
1.2.696.1. Suggestions¶
Use empty() on the data
Compare the variable with a default value, such as an empty array
1.2.696.2. Specs¶
Short name |
Performances/NotCountNull |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.697. Optimize Explode()¶
By default, explode() breaks the whole string into smaller strings, and returns the array. When not all the elements of the returned array are necessary, using the third argument of explode() speeds up the process, by removing unnecessary work.
<?php
$string = '1,2,3,4,5,';
// explode() returns 2 elements, which are then assigned to the list() call.
list($a, $b) = explode(',', $string, 2);
// explode() returns 6 elements, only two of which are then assigned to the list() call. The rest are discarded.
list($a, $b) = explode(',', $string, 2);
// it is not possible to skip the first elements, but it is possible to skip the last ones.
echo explode(',', $string, 2)[1];
// This protects PHP, in case $string ends up with a lot of commas
$string = foo(); // usually '1,2' but not known
list($a, $b) = explode(',', $string, 2);
?>
Limiting explode() has no effect when the operation is already exact : it simply prevents explode() to cut more than needed if the argument is unexpectedly large.
This optimisation applies to split(), preg_split() and mb_split(), too.
This is a micro optimisation, unless the exploded string is large.
1.2.697.1. Suggestions¶
Add a limit to explode() call
1.2.697.2. Specs¶
Short name |
Performances/OptimizeExplode |
Rulesets |
|
Exakat since |
2.1.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Available in |
1.2.698. Use PHP7 Encapsed Strings¶
PHP 7 has optimized the handling of double-quoted strings. In particular, double-quoted strings are much less memory hungry than classic concatenations.
PHP allocates memory at the end of the double-quoted string, making only one call to the allocator. On the other hand, concatenations are allocated each time they include dynamic content, leading to higher memory consumption.
<?php
$bar = 'bar';
/* PHP 7 optimized this */
$a = "foo and $bar";
/* This is PHP 5 code (aka, don't use it) */
$a = 'foo and ' . $bar;
// Constants can't be used with double quotes
$a = 'foo and ' . __DIR__;
$a = foo and __DIR__; // __DIR__ is not interpolated
?>
Concatenations are still needed with constants, static constants, magic constants, functions, static properties or static methods.
See also PHP 7 performance improvements (3/5): Encapsed strings optimization.
1.2.698.1. Specs¶
Short name |
Performances/PHP7EncapsedStrings |
Rulesets |
|
Exakat since |
1.0.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.699. Always Use Function With array_key_exists()¶
array_key_exists() has been granted a special VM opcode, and is much faster. This applies to PHP 7.4 and more recent.
It requires that array_key_exists() is statically resolved, either with an initial \, or a use function expression. This doesn’t affect the global namespace.
<?php
namespace my/name/space;
// do not forget the 'function' keyword, or it will apply to classes.
use function array_key_exists as foo; // the alias is not necessary, and may be omitted.
// array_key_exists is aliased to foo :
$c = foo($a, $b);
// This call requires a fallback to global, and will be slow.
$c = array_key_exists($a, $b);
?>
This analysis is related to Php/ShouldUseFunction, and is a special case, that only concerns array_key_exists().
See also Add array_key_exists to the list of specialy compiled functions.
1.2.699.1. Suggestions¶
Use the use command for arrray_key_exists(), at the beginning of the script
Use an initial before array_key_exists()
Remove the namespace
1.2.699.2. Specs¶
Short name |
Performances/Php74ArrayKeyExists |
Rulesets |
|
Exakat since |
1.8.4 |
PHP Version |
7.4+ |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.700. Pre-increment¶
When possible, use the pre-increment operator (
++$ior--$i) instead of the post-increment operator ($i++or$i--).
The latter needs an extra memory allocation that costs about 10% of performances.
<?php
// ++$i should be preferred over $i++, as current value is not important
for($i = 0; $i <10; ++$i) {
// do Something
}
// ++$b and $b++ have different impact here, since $a will collect $b + 1 or $b, respectively.
$a = $b++;
?>
This is a micro-optimisation. However, its usage is so widespread, including within loops, that it may eventually have an significant impact on execution time. As such, it is recommended to adopt this rule, and only consider changing legacy code as they are refactored for other reasons.
1.2.700.1. Suggestions¶
Use the pre increment when the new value is not reused.
1.2.700.2. Specs¶
Short name |
Performances/PrePostIncrement |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Examples |
|
Available in |
1.2.701. Regex On Arrays¶
Avoid using a loop with arrays of regex or values. There are several PHP function which work directly on arrays, and much faster.
preg_grep() is able to extract all matching strings from an array, or non-matching strings. This usually saves a loop over the strings.
preg_filter() is able to extract all strings from an array, matching at least one regex in an array. This usually saves a double loop over the strings and the regex. The trick here is to provide ‘$0’ as replacement, leading preg_filter() to replace the found string by itself.
Finally, preg_replace_callback() an preg_replace_callback_array() are also able to apply an array of regex to an array of strings, and then, apply callbacks to the found values.
<?php
$regexs = ['/ab+c/', '/abd+/', '/abe+/'];
$strings = ['/abbbbc/', '/abd/', '/abeee/'];
// Directly extract all strings that match one regex
foreach($regexs as $regex) {
$results[] = preg_grep($regex, $strings);
}
// extract all matching regex, by string
foreach($strings as $string) {
$results[] = preg_filter($regexs, array_fill(0, count($regexs), '\$0'), $string);
}
// very slow way to get all the strings that match a regex
foreach($regexs as $regex) {
foreach($strings as $string) {
if (preg_match($regex, $string)) {
$results[] = $string;
}
}
}
?>
See also preg_filter.
1.2.701.1. Suggestions¶
Apply preg_match() to an array of string or regex, via preg_filter() or preg_grep().
Apply preg_match() to an array of string or regex, via preg_replace_callback() or preg_replace_callback_array().
1.2.701.2. Specs¶
Short name |
Performances/RegexOnArrays |
Rulesets |
|
Exakat since |
1.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.702. Processing Collector¶
When accumulating data in a variable, within a loop, it is slow to apply repeatedly a function to the variable.
The example below illustrate the problem : $collector is build with element from $array. $collector actually gets larger and larger, slowing the in_array() call each time.
It is better to apply the preg_replace() to $a, a short variable, and then, add $a to the collector.
<?php
// Fast way
$collector = '';
foreach($array as $a){
$a = preg_replace('/__(.*?)__/', '<b>\$1</b>', $a);
$collector .= $a;
}
// Slow way
$collector = '';
foreach($array as $a){
$collector .= $a;
$collector = preg_replace('/__(.*?)__/', '<b>\$1</b>', $collector);
}
?>
1.2.702.1. Suggestions¶
Avoid applying the checks on the whole data, rather on the diff only.
1.2.702.2. Specs¶
Short name |
Performances/RegexOnCollector |
Rulesets |
|
Exakat since |
1.2.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.703. Simple Switch¶
Switches are faster when relying only on integers or strings.
Since PHP 7.2, simple switches that use only strings or integers are optimized. The gain is as great as the switch is big.
<?php
// Optimized switch.
switch($b) {
case "a":
break;
case "b":
break;
case "c":
break;
case "d":
break;
default :
break;
}
// Unoptimized switch.
// Try moving the foo() call in the default, to keep the rest of the switch optimized.
switch($c) {
case "a":
break;
case foo($b):
break;
case "c":
break;
case "d":
break;
default :
break;
}
?>
1.2.703.1. Suggestions¶
Split the switch between literal and dynamic cases
Remove the dynamic cases from the switch
See also and PHP 7.2’s “switch” optimisations.
1.2.703.2. Specs¶
Short name |
Performances/SimpleSwitch |
Rulesets |
|
Exakat since |
1.0.1 |
PHP Version |
7.2+ |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Available in |
1.2.704. Slow Functions¶
Avoid using those slow native PHP functions, and replace them with alternatives.
<?php
$array = source();
// Slow extraction of distinct values
$array = array_unique($array);
// Much faster extraction of distinct values
$array = array_keys(array_count_values($array));
?>
Slow Function |
Faster |
array_diff() array_intersect() array_key_exists() array_map() array_search() array_udiff() array_uintersect() array_unshift() array_walk() in_array() preg_replace() strstr() uasort() uksort() usort() array_unique() |
foreach() foreach() isset() and array_key_exists() foreach() array_flip() and isset() Use another way Use another way Use another way foreach() isset() strpos() strpos() Use another way Use another way Use another way array_keys() and array_count_values() |
array_unique() has been accelerated in PHP 7.2 and may be used directly from this version on : Optimize `array_unique() <https://github.com/php/php-src/commit/6c2c7a023da4223e41fea0225c51a417fc8eb10d>`_.
array_key_exists() has been accelerated in PHP 7.4 and may be used directly from this version on : Implement ZEND_ARRAY_KEY_EXISTS opcode to speed up `array_key_exists() <https://github.com/php/php-src/pull/3360>`_.
1.2.704.1. Suggestions¶
Replace the slow function with a faster version
Remove the usage of the slow function
1.2.704.2. Specs¶
Short name |
Performances/SlowFunctions |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
ClearPHP |
|
Examples |
|
Available in |
1.2.705. strpos() Too Much¶
The longer the haystack (the searched string), the more efficient is that trick. The string has to be 10k or more to have impact, unless it is in a loop.
<?php
// This always reads the same amount of string
if (substr($html, 0, 6) === '<html>') {
}
// When searching for a single character, checking with a known position ($string[$position]) is even faster
if ($html[0] === '<') {
}
// With strpos(), the best way is to search for something that exist, and use absence as worst case scenario
if (strpos($html, '<html>') > 0) {
} else {
//
}
// When the search fails, the whole string has been read
if (strpos($html, '<html>') === 0) {
}
?>
This applies to stripos() too.
1.2.705.1. Suggestions¶
Check for presence, and not for absence
use substr() and compare the extracted string
For single chars, try using the position in the string
1.2.705.2. Specs¶
Short name |
Performances/StrposTooMuch |
Rulesets |
|
Exakat since |
1.2.8 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.706. Substring First¶
Always start by reducing a string before applying some transformation on it. The shorter string will be processed faster.
<?php
// fast version
$result = strtolower(substr($string, $offset, $length));
// slower version
$result = substr(strtolower($string), $offset, $length);
?>
The gain produced here is greater with longer strings, or greater reductions. They may also be used in loops. This is a micro-optimisation when used on short strings and single string reductions.
This works with any reduction function instead of substr(), like trim(), iconv(), etc.
1.2.706.1. Suggestions¶
Always reduce the string first, then apply some transformation
1.2.706.2. Specs¶
Short name |
Performances/SubstrFirst |
Rulesets |
|
Exakat since |
1.0.1 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.707. Use array_slice()¶
Array_slice is de equivalent of substr() for arrays.
array_splice() is also possible, to remove a portion of array inside the array, not at the ends. This has no equivalent for strings.
<?php
$array = range(0, 9);
// Extract the 5 first elements
print_r(array_slice($array, 0, 5));
// Extract the 4 last elements
print_r(array_slice($array, -4));
// Extract the 2 central elements : 4 and 5
print_r(array_splice($array, 4, 2));
// slow way to remove the last elementst of an array
for($i = 0; $i < 4) {
array_pop($array);
}
?>
See also array_slice and array_splice.
1.2.707.1. Specs¶
Short name |
Performances/UseArraySlice |
Rulesets |
|
Exakat since |
1.9.5 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.708. Use The Blind Var¶
When in a loop, it is faster to rely on the blind var, rather than the original source.
When the key is referenced in the foreach loop, it is faster to use the available container to access a value for reading.
Note that it is also faster to use the value with a reference to handle the writings.
<?php
// Reaching $source[$key] via $value is faster
foreach($source as $key => $value) {
$coordinates = array('x' => $value[0],
'y' => $value[1]);
}
// Reaching $source[$key] via $source is slow
foreach($source as $key => $value) {
$coordinates = array('x' => $source[$key][0],
'y' => $source[$key][1]);
}
?>
1.2.708.1. Suggestions¶
Use the blind var
1.2.708.2. Specs¶
Short name |
Performances/UseBlindVar |
Rulesets |
|
Exakat since |
1.2.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.709. time() Vs strtotime()¶
time() is actually faster than strtotime() with ‘now’ key string.
<?php
// Faster version
$a = time();
// Slower version
$b = strtotime('now');
?>
This is a micro-optimisation. Relative gain is real, but small unless the function is used many times.
1.2.709.1. Suggestions¶
Replace strtotime() with time(). Do not change strtotime() with other value than ‘now’.
1.2.709.2. Specs¶
Short name |
Performances/timeVsstrtotime |
Rulesets |
|
Exakat since |
0.8.7 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.710. PHP Alternative Syntax¶
Identify the usage of alternative syntax in the code, for If then, Switch, While, For and Foreach.
<?php
// Normal syntax
if ($a == 1) {
print $a;
}
// Alternative syntax : identical to the previous one.
if ($a == 1) :
print $a;
endif;
?>
See also Alternative syntax.
1.2.710.1. Specs¶
Short name |
Php/AlternativeSyntax |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
Very high |
Available in |
1.2.711. Argon2 Usage¶
Argon2 is an optionally compiled password hashing API.
Argon2 has been added to the password hashing API in PHP 7.2.
It is not available in older version. It also requires PHP to be compiled with the –with-password-argon2 option.
<?php
// Hashing a password with argon2
$hash = password_hash('password', PASSWORD_ARGON2I, ['memory_cost' => 1<<17,
'time_cost' => PASSWORD_ARGON2_DEFAULT_TIME_COST,
'threads' => PASSWORD_ARGON2_DEFAULT_THREADS]);
?>
See also Argon2 Password Hash.
1.2.711.1. Specs¶
Short name |
Php/Argon2Usage |
Rulesets |
|
Exakat since |
1.0.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.712. array_key_exists() Works On Arrays¶
array_key_exists() requires arrays as second argument. Until PHP 7.4, objects were also allowed, yet it is now deprecated.
<?php
// Valid way to check for key
$array = ['a' => 1];
var_dump(array_key_exists('a', $array))
// Deprecated since PHP 7.4
$object = new Stdclass();
$object->a = 1;
var_dump(array_key_exists('a', $object))
?>
See also array_key_exists() with objects, and array_key_exists.
1.2.712.1. Suggestions¶
Use the (array) cast to turn the object into an array
Use the native PHP function proprety_exists() or isset() on the property to check them.
1.2.712.2. Specs¶
Short name |
Php/ArrayKeyExistsWithObjects |
Rulesets |
|
Exakat since |
1.9.0 |
PHP Version |
All |
PHP deprecated |
7.4 |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.713. Assert Function Is Reserved¶
Avoid defining an
assertfunction in namespaces.
While they work fine when the assertions are active (zend.assertions=1), calls to unqualified assert are optimized away when assertions are not active.
Since PHP 7.3, a fatal error is emitted : Defining a custom `assert() <https://www.php.net/assert>`_ function is deprecated, as the function has special semantics.
<?php
// Run this with zend.assertions=1 and
// Then run this with zend.assertions=0
namespace Test {
function assert() {
global $foo;
$foo = true;
}
}
namespace Test {
assert();
var_dump(isset($foo));
}
?>
See also assert and User-defined assert function is optimized away with zend.assertions=-1.
1.2.713.1. Suggestions¶
Rename the custom function with another name
1.2.713.2. Specs¶
Short name |
Php/AssertFunctionIsReserved |
Rulesets |
|
Exakat since |
1.3.9 |
PHP Version |
All |
PHP deprecated |
7.2 |
Severity |
Critical |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.714. Assertions¶
Usage of assertions, to add checks within PHP code.
Assertions should be used as a debugging feature only. You may use them for sanity-checks that test for conditions that should always be TRUE and that indicate some programming errors if not or to check for the presence of certain features like extension functions or certain system limits and features.
<?php
function foo($string) {
assert(!empty($string), 'An empty string was provided!');
echo '['.$string.']';
}
?>
See also assert.
1.2.714.1. Specs¶
Short name |
Php/AssertionUsage |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.715. Assign With And Precedence¶
The lettered logical operators yield to assignation. It may collect less information than expected.
It is recommended to use the &&, ^ and || operators, instead of and, or and xor, to prevent confusion.
<?php
// The expected behavior is
// The following are equivalent
$a = $b && $c;
$a = ($b && $c);
// The unexpected behavior is
// The following are equivalent
$a = $b and $c;
($a = $b) and $c;
?>
See also Operator Precedence.
1.2.715.1. Suggestions¶
Always use symbol && rather than letter and
To be safe, add parenthesis to enforce priorities
1.2.715.2. Specs¶
Short name |
Php/AssignAnd |
Rulesets |
|
Exakat since |
0.12.4 |
PHP Version |
All |
Severity |
Critical |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Examples |
|
Available in |
1.2.716. Assumptions¶
Assumptions in the code, that leads to possible bugs.
Some conditions may be very weak, and lead to errors. For example, the code below checks that the variable $a is not null, then uses it as an array. There is no relationship between ‘not null’ and ‘being an array’, so this is an assumption.
<?php
// Assumption : if $a is not null, then it is an array. This is not always the case.
function foo($a) {
if ($a !== null) {
echo $a['name'];
}
}
// Assumption : if $a is not null, then it is an array. Here, the typehint will ensure that it is the case.
// Although, a more readable test is is_array()
function foo(?array $a) {
if ($a !== null) {
echo $a['name'];
}
}
?>
1.2.716.1. Suggestions¶
Make the context of the code more explicit
Use a class to handle specific array index
Avoid using named index by using foreach()
See also and From assumptions to assertions.
1.2.716.2. Specs¶
Short name |
Php/Assumptions |
Rulesets |
|
Exakat since |
2.1.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.717. Autoloading¶
Usage of the autoloading feature of PHP.
<?php
spl_autoload_register('my_autoloader');
// Old way to autoload. Deprecated in PHP 7.2
function __autoload($class ) {}
?>
Defining the __autoload() function is obsolete since PHP 7.2.
See also __autoload.
1.2.717.1. Specs¶
Short name |
Php/AutoloadUsage |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.718. Avoid get_object_vars()¶
get_object_vars() changes behavior between PHP 7.3 and 7.4. It also behaves different within and outside a class.
<?php
// Code from Doug Bierer
$obj = new ArrayObject(['A' => 1,'B' => 2,'C' => 3]);
var_dump($obj->getArrayCopy());
var_dump(get_object_vars($obj));
?>
See also get_object_vars script on 3V4L and The Strange Case of `ArrayObject <https://phptraining.net/articles/strange_case_of_array_object>`_.
1.2.718.1. Suggestions¶
Use ArrayObject and getArrayCopy() method
1.2.718.2. Specs¶
Short name |
Php/AvoidGetobjectVars |
Rulesets |
|
Exakat since |
2.2.1 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.719. Avoid mb_dectect_encoding()¶
mb_dectect_encoding() is bad at guessing encoding.
For example, UTF-8 and ISO-8859-1 share some common characters : when a string is build with them it is impossible to differentiate the actual encoding.
<?php
$encoding = mb_encoding_detect($_GET['name']);
?>
See also mb_encoding_detect, PHP vs. The Developer: Encoding Character Sets, DPC2019: Of representation and interpretation: A unified theory - Arnout Boks.
1.2.719.1. Suggestions¶
Store and transmit the data format
1.2.719.2. Specs¶
Short name |
Php/AvoidMbDectectEncoding |
Rulesets |
|
Exakat since |
1.8.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.720. Avoid Real¶
PHP has two float data type : real and double.
realis rarely used, and might be deprecated in PHP 7.4.
To prepare code, avoid using is_real() and the (real) typecast.
<?php
// safe way to check for float
if (!is_float($a)) {
$a = (float) $a;
}
// Avoid doing that
if (!is_real($a)) {
$a = (real) $a;
}
?>
See also PHP RFC: Deprecations for PHP 7.4.
1.2.720.1. Suggestions¶
Replace is_real() by is_float()
Replace (real) by (float)
1.2.720.2. Specs¶
Short name |
Php/AvoidReal |
Rulesets |
|
Exakat since |
1.3.9 |
PHP Version |
8.0- |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.721. Avoid set_error_handler $context Argument¶
Avoid configuring set_error_handler() with a method that accepts 5 arguments. The last argument,
$errcontext, is deprecated since PHP 7.2, and will be removed later.
<?php
// setting error_handler with an incorrect closure
set_error_handler(function($errno, $errstr, $errfile, $errline) {});
// setting error_handler with an incorrect closure
set_error_handler(function($errno, $errstr, $errfile, $errline, $errcontext) {});
?>
See also set_error_handler();
1.2.721.1. Suggestions¶
Remove the 6th argument of registered handlers.
1.2.721.2. Specs¶
Short name |
Php/AvoidSetErrorHandlerContextArg |
Rulesets |
|
Exakat since |
1.0.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Examples |
|
Available in |
1.2.722. Use random_int()¶
rand() and mt_rand() should be replaced with random_int().
At worse, rand() should be replaced with mt_rand(), which is a drop-in replacement and srand() by mt_srand().
random_int() replaces rand(), and has no seeding function like srand().
Other sources of entropy that should be replaced by random_int() : microtime(), uniqid(), time(). Those a often combined with hashing functions and mixed with other sources of entropy, such as a salt.
<?php
// Avoid using this
$random = rand(0, 10);
// Drop-in replacement
$random = mt_rand(0, 10);
// Even better but different :
// valid with PHP 7.0+
try {
$random = random_int(0, 10);
} catch (\Exception $e) {
// process case of not enoug random values
}
// This is also a source of entropy, based on srand()
// random_int() is a drop-in replacement here
$a = sha256(uniqid());
?>
Since PHP 7, random_int() along with random_bytes(), provides cryptographically secure pseudo-random bytes, which are good to be used
when security is involved. openssl_random_pseudo_bytes() may be used when the OpenSSL extension is available.
1.2.722.1. Suggestions¶
Use random_bytes() and randon_int(). At least, use them as a base for random data, and then add extra prefix and suffix, and a hash call on top.
1.2.722.2. Specs¶
Short name |
Php/BetterRand |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Instant (5 mins) |
Precision |
Very high |
Examples |
|
Available in |
1.2.723. Calling Static Trait Method¶
Calling directly a static method, defined in a trait is deprecated. It emits a deprecation notice in PHP 8.1.
<?php
trait T {
public static function t() {
//
}
}
T::t();
?>
Calling the same method, from the class point of view is valid.
See also PHP RFC: Deprecations for PHP 8.1.
1.2.723.1. Suggestions¶
Call the method from one of the class using the trait
Move the method to a class
1.2.723.2. Specs¶
Short name |
Php/CallingStaticTraitMethod |
Rulesets |
|
Exakat since |
2.2.5 |
PHP Version |
With PHP 8.1 and older |
PHP deprecated |
8.1 |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Unknown |
Available in |
1.2.724. Cant Use Return Value In Write Context¶
<?php
function foo($boolean) {
return $boolean;
}
// Valid since PHP 5.5
echo empty(foo(true)) : 'true' : 'false';
?>
This also applies to methodcalls, static or not.
See also Cant Use Return Value In Write Context.
1.2.724.1. Specs¶
Short name |
Php/CantUseReturnValueInWriteContext |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
5.5+ |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.725. Use Lower Case For Parent, Static And Self¶
parent, static and self are traditionally written in lowercase only. Mixed case and Upper case are both valid, though.
<?php
class foo {
const aConstante = 233;
function method() {
// Wrong case, error with PHP 5.4.* and older
echo SELF::aConstante;
// Always right.
echo self::aConstante;
}
}
?>
Until PHP 5.5, non-lowercase version of those keywords are generating a bug.
1.2.725.1. Suggestions¶
Upgrade to PHP 5.6 or more recent
1.2.725.2. Specs¶
Short name |
Php/CaseForPSS |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
5.5- |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.726. Cast Unset Usage¶
Usage of the (unset) cast operator. It is removed in PHP 8.0, and was deprecated since PHP 7.2.0.
<?php
$a = 1;
(unset) $a;
// functioncall is OK
unset($a);
?>
See also Unset casting.
1.2.726.1. Suggestions¶
Replace (unset) with a call to unset().
Remove the unset call altogether.
1.2.726.2. Specs¶
Short name |
Php/CastUnsetUsage |
Rulesets |
|
Exakat since |
2.1.8 |
PHP Version |
8.0- |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.727. Cast Usage¶
List of all cast usage.
PHP does not require (or support) explicit type definition in variable declaration; a variable’s type is determined by the context in which the variable is used.
<?php
if (is_int($_GET['x'])) {
$number = (int) $_GET['x'];
} else {
error_display('a wrong value was provided for "x"');
}
?>
Until PHP 7.2, a (unset) operator was available. It had the same role as unset() as a function.
See also Type Juggling and unset.
1.2.727.1. Specs¶
Short name |
Php/CastingUsage |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.728. Class Const With Array¶
Constant defined with const keyword may be arrays but only stating with PHP 5.6. Define never accept arrays : it only accepts scalar values.
1.2.728.1. Specs¶
Short name |
Php/ClassConstWithArray |
Rulesets |
CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, All |
Exakat since |
0.8.4 |
PHP Version |
5.5+ |
Severity |
Critical |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.729. Class Function Confusion¶
Avoid classes and functions bearing the same name.
When functions and classes bear the same name, calling them may be confusing. This may also lead to forgotten ‘new’ keyword.
<?php
class foo {}
function foo() {}
// Forgetting the 'new' operator is easy
$object = new foo();
$object = foo();
?>
1.2.729.1. Suggestions¶
Use a naming convention to distinguish functions and classes
Rename the class or the function (or both)
Use an alias with a use expression
1.2.729.2. Specs¶
Short name |
Php/ClassFunctionConfusion |
Rulesets |
|
Exakat since |
0.10.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.730. Close Tags¶
PHP manual recommends that script should be left open, without the final closing ?>. This way, one will avoid the infamous bug ‘Header already sent’, associated with left-over spaces, that are lying after this closing tag.
1.2.730.1. Specs¶
Short name |
Php/CloseTags |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
ClearPHP |
|
Available in |
1.2.731. Close Tags Consistency¶
PHP scripts may omit the final closing tag.
This is a convention, used to avoid the infamous ‘headers already sent’ error message, that appears when a script with extra invisible spaces is included before actually emitting the headers.
The PHP manual recommends : If a file is pure PHP code, it is preferable to omit the PHP closing tag at the end of the file.. (See PHP Tags):
.. code-block:: php
<?php
class foo {
}
1.2.731.1. Specs¶
Short name |
Php/CloseTagsConsistency |
Rulesets |
|
Exakat since |
0.9.3 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.732. Closure May Use $this¶
$this is automatically accessible to closures.
When closures were introduced in PHP, they couldn’t use the $this variable, making is cumbersome to access local properties when the closure was created within an object.
<?php
// Invalid code in PHP 5.4 and less
class Test
{
public function testing()
{
return function() {
var_dump($this);
};
}
}
$object = new Test;
$function = $object->testing();
$function();
?>
This is not the case anymore since PHP 5.4.
See also Anonymous functions.
1.2.732.1. Specs¶
Short name |
Php/ClosureThisSupport |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
5.4- |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.733. Coalesce¶
Usage of coalesce operator, in PHP since PHP 5.3.
Note that the coalesce operator is a special case of the ternary operator.
<?php
// Coalesce operator, since PHP 5.3
$a = $b ?: 'default value';
// Equivalent to $a = $b ? $b : 'default value';
?>
See also Ternary Operator.
1.2.733.1. Specs¶
Short name |
Php/Coalesce |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
7.0+ |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.734. Coalesce Equal¶
Usage of coalesce assignement operator. The operator is available in PHP since PHP 7.4.
<?php
// Coalesce operator, since PHP 5.3
$a ??= 'default value';
// Equivalent to the line above
$a = $a ?? 'default value';
?>
See also Ternary Operator.
1.2.734.1. Suggestions¶
Use the short assignement syntax
1.2.734.2. Specs¶
Short name |
Php/CoalesceEqual |
Rulesets |
CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, CompatibilityPHP70, CompatibilityPHP71, CompatibilityPHP72, CompatibilityPHP73, All |
Exakat since |
2.0.4 |
PHP Version |
7.4+ |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
Very high |
Available in |
1.2.735. Compact Inexistant Variable¶
Compact() doesn’t warn when it tries to work on an inexistant variable. It just ignores the variable.
This behavior changed in PHP 7.3, and compact() now emits a warning when the compacted variable doesn’t exist.
<?php
function foo($b = 2) {
$a = 1;
// $c doesn't exists, and is not compacted.
return compact('a', 'b', 'c');
}
?>
For performances reasons, this analysis only works inside methods and functions.
See also compact and PHP RFC: Make compact function reports undefined passed variables.
1.2.735.1. Suggestions¶
Fix the name of variable in the compact() argument list
Remove the name of variable in the compact() argument list
1.2.735.2. Specs¶
Short name |
Php/CompactInexistant |
Rulesets |
|
Exakat since |
1.2.9 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.736. Concat And Addition¶
Precedence between addition and concatenation has changed. In PHP 7.4, addition has precedence, and before, addition and concatenation had the same precedence.
From the RFC : Currently the precedence of '.', '+' and '-' operators are equal. Any combination of these operators are simply evaluated left-to-right.
This is counter-intuitive though: you rarely want to add or subtract concatenated strings which in general are not numbers. However, given PHP’s capability of seamlessly converting an integer to a string, concatenation of these values is desired.``
<?php
// Extracted from the RFC
echo sum: . $a + $b;
// current behavior: evaluated left-to-right
echo (sum: . $a) + $b;
// desired behavior: addition and subtraction have a higher precendence
echo sum : . ($a + $b);
?>
This analysis reports any addition and concatenation that are mixed, without parenthesis. Addition also means substraction here, aka using + or -.
The same applies to bitshift operations, << and >>. There is no RFC for this change.
See also Change the precedence of the concatenation operator.
1.2.736.1. Suggestions¶
Add parenthesis around the addition to ensure its expected priority
Move the addition outside the concatenation
1.2.736.2. Specs¶
Short name |
Php/ConcatAndAddition |
Rulesets |
Analyze, CE, CI-checks, CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, CompatibilityPHP70, CompatibilityPHP71, CompatibilityPHP72, CompatibilityPHP73, CompatibilityPHP74, CompatibilityPHP80, Top10, All |
Exakat since |
1.8.0 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.737. Const With Array¶
The const keyword supports array. This feature was added in PHP 5.6.
The array must be filled with other constants. It may also be build using the ‘+’ operator.
<?php
const PRIMES = [2, 3, 5, 7];
class X {
const TWENTY_THREE = 23;
const MORE_PRIMES = PRIMES + [11, 13, 17, 19];
const EVEN_MORE_PRIMES = self::MORE_PRIMES + [self::TWENTY_THREE];
}
?>
See also Class Constants and Constants Syntax.
1.2.737.1. Specs¶
Short name |
Php/ConstWithArray |
Rulesets |
CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, All |
Exakat since |
0.8.4 |
PHP Version |
5.5+ |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.738. Constant Scalar Expression¶
Since PHP 5.6, it is possible to use expression with Constants and default values. One may only use simple operators.
<?php
const THREE = 1 + 2;
const ARRAY = array(1,2,3);
// dynamic version
define('ARRAY', array(1,2,3));
// constant scalar expression are available for default values
function foo($a = 1 + M_PI) {
}
?>
1.2.738.1. Suggestions¶
Upgrade to PHP 7.0
Use a special value as the default value, and turn it into the actual value at constructor time
See also and New features..
1.2.738.2. Specs¶
Short name |
Php/ConstantScalarExpression |
Rulesets |
none |
Exakat since |
0.8.4 |
PHP Version |
With PHP 5.6 and older |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
Very high |
Available in |
1.2.739. Cookies Variables¶
Cookies names, used across the application.
<?php
if (isset($_COOKIE['myCookie'])) {
// Usual method for reading and setting cookies
$_COOKIE['myCookie']++;
}
// Usual method for writing cookies
setcookie('myCookie', $value);
?>
See also setcookie.
1.2.739.1. Specs¶
Short name |
Php/CookiesVariables |
Rulesets |
|
Exakat since |
0.12.16 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.740. Use is_countable¶
is_countable() checks if a variables holds a value that can be counted. It is recommended to use it before calling count().
is_countable() accepts arrays and object whose class implements countable.
<?php
function foo($arg) {
if (!is_countable($arg)) {
// $arg cannot be passed to count()
return 0
}
return count($arg);
}
function bar($arg) {
if (!is_array($arg) and !$x instanceof \Countable) {
// $arg cannot be passed to count()
return 0
}
return count($arg);
}
?>
1.2.740.1. Suggestions¶
Use is_countable()
Create a compatibility function that replaces is_countable() until the code is ready for PHP 7.3
See also and PHP RFC: is_countable.
1.2.740.2. Specs¶
Short name |
Php/CouldUseIsCountable |
Rulesets |
|
Exakat since |
1.3.8 |
PHP Version |
With PHP 7.3 and more recent |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.741. Could Use Promoted Properties¶
Promoted properties reduce PHP code at __construct() time. This feature is available in PHP 8.0.
<?php
class x {
function __construct($a, $b) {
// $a argument may be promoted to property $c
$this->c = $a;
// $b argument cannot be upgraded to property, as it is updated.
// Move the addition to the new call, or keep the syntax below
$this->d = $b + 2;
}
}
?>
1.2.741.1. Suggestions¶
Update the constructor syntax, and remove the property specification.
See also PHP 8: Constructor property promotion and PHP RFC: Constructor Property Promotion.
1.2.741.2. Specs¶
Short name |
Php/CouldUsePromotedProperties |
Rulesets |
|
Exakat since |
2.1.9 |
PHP Version |
With PHP 8.0 and more recent |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.742. Crc32() Might Be Negative¶
crc32() may return a negative number, on 32 bits platforms.
According to the manual : Because PHP's integer type is signed many CRC32 checksums will result in negative integers on 32 bits platforms. On 64 bits installations, all crc32() results will be positive integers though.
<?php
// display the checksum with %u, to make it unsigned
echo sprintf('%u', crc32($str));
// turn the checksum into an unsigned hexadecimal
echo dechex(crc32($str));
// avoid concatenating crc32 to a string, as it may be negative on 32bits platforms
echo 'prefix'.crc32($str);
?>
See also crc32().
1.2.742.1. Specs¶
Short name |
Php/Crc32MightBeNegative |
Rulesets |
|
Exakat since |
0.11.0 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.743. Crypto Usage¶
Usage of cryptography and hashes functions.
The functions listed are the native PHP functions, and do not belong to a specific extension, like OpenSSL, mcrypt or mhash.
Cryptography and hashes are mainly used for storing sensitive data, such as passwords, or to verify authenticity of data. They may also be used for name-randomization with cache.
<?php
if (md5($_POST['password']) === $row['password_hash']) {
user_login($user);
} else {
error('Wrong password');
}
?>
See also Cryptography Extensions.
1.2.743.1. Specs¶
Short name |
Php/CryptoUsage |
Rulesets |
|
Exakat since |
1.0.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.744. Date Formats¶
Inventory of date formats used in the code.
Date format are detected with
<?php
$time = time();
// This is a formated date
echo date('r', $time);
?>
See also Date and Time.
1.2.744.1. Specs¶
Short name |
Php/DateFormats |
Rulesets |
|
Exakat since |
0.12.16 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.745. Encoding Usage¶
Usage of declare(encoding = );.
<?php
// Setting encoding for the file;
declare(encoding = 'UTF-8');
?>
See also declare.
1.2.745.1. Specs¶
Short name |
Php/DeclareEncoding |
Rulesets |
Appinfo, CE, Preferences, All |
Exakat since |
0.12.1 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.746. strict_types Preference¶
strict_typesis a PHP mode where typehint are enforced strictly or weakly. By default, it is weak typing, allowing backward compatibility with previous versions.
This analysis reports if strict_types are used systematically or not. strict_types affects the calling file, not the definition file.
<?php
// define strict_types
declare(strict_types = 1);
foo(1);
?>
See also Strict typing.
1.2.746.1. Specs¶
Short name |
Php/DeclareStrict |
Rulesets |
Appinfo, CE, Preferences, All |
Exakat since |
0.12.2 |
PHP Version |
7.0+ |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.747. Declare strict_types Usage¶
Usage of
strict_types. By default, PHP attempts to change the original type to match the type specified by the type-declaration. With an explicitstrict_typesdeclaration, PHP ensures that the incoming argument has the exact type.
strict_types were introduced in PHP 7.0.
<?php
// Setting strict_types;
declare(strict_types = 1);
function foo(int $i) {
echo $i;
}
// Always valid : displays 1
foo(1);
// with strict types, this emits an error
// without strict types, this displays 1
foo(1.7);
?>
See also declare.
1.2.747.1. Specs¶
Short name |
Php/DeclareStrictType |
Rulesets |
Appinfo, CE, Preferences, All |
Exakat since |
0.12.1 |
PHP Version |
7.0+ |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.748. Ticks Usage¶
Usage of declare(ticks = );.
<?php
// Setting ticks value
declare(ticks = 'UTF-8');
?>
See also declare.
1.2.748.1. Specs¶
Short name |
Php/DeclareTicks |
Rulesets |
Appinfo, CE, Preferences, All |
Exakat since |
0.12.1 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
Very high |
Available in |
1.2.749. Define With Array¶
PHP 7.0 has the ability to define an array as a constant, using the define() native call. This was not possible until that version, only with the const keyword.
<?php
//Defining an array as a constant
define('MY_PRIMES', [2, 3, 5, 7, 11]);
?>
1.2.749.1. Specs¶
Short name |
Php/DefineWithArray |
Rulesets |
CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, All |
Exakat since |
0.8.4 |
PHP Version |
7.0+ |
Severity |
Critical |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.750. Deprecated PHP Functions¶
The following functions are deprecated. It is recommended to stop using them now and replace them with a durable equivalent.
Note that these functions may be still usable : they generate warning that help tracking their usage in the log. To eradicate their usage, watch the logs, and update any deprecated warning. This way, the code won’t be stuck when the function is actually removed from PHP.
<?php
// This is the current function
list($day, $month, $year) = explode('/', '08/06/1995');
// This is deprecated
list($day, $month, $year) = split('/', '08/06/1995');
?>
1.2.750.1. Suggestions¶
Replace those deprecated with modern syntax
Stop using deprecated syntax
1.2.750.2. Specs¶
Short name |
Php/Deprecated |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
ClearPHP |
|
Examples |
|
Available in |
1.2.751. Detect Current Class¶
Detecting the current class should be done with self::class or static::class operator.
__CLASS__ may be replaced by self\:\:class.
get_called_class() may be replaced by static\:\:class.
__CLASS__ and get_called_class() are set to be deprecated in PHP 7.4.
<?php
class X {
function foo() {
echo __CLASS__.\n; // X
echo self::class.\n; // X
echo get_called_class().\n; // Y
echo static::class.\n; // Y
}
}
class Y extends X {}
$y = new Y();
$y->foo();
?>
See also PHP RFC: Deprecations for PHP 7.4.
1.2.751.1. Suggestions¶
Use the self::class operator to detect the current class name, instead of __CLASS__ and get_class().
Use the static::class operator to detect the current called class name, instead of get_called_class().
1.2.751.2. Specs¶
Short name |
Php/DetectCurrentClass |
Rulesets |
|
Exakat since |
1.3.8 |
PHP Version |
8.0- |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
Very high |
Available in |
1.2.752. Direct Call To __clone()¶
Direct call to magic method __clone() was forbidden. It is allowed since PHP 7.0.
From the RFC : Doing calls like $obj->`__clone( <https://www.php.net/manual/en/language.oop5.magic.php>`_ ) is now allowed. This was the only magic method that had a compile-time check preventing some calls to it, which doesn't make sense. If we allow all other magic methods to be called, there's no reason to forbid this one.
<?php
class Foo {
function __clone() {}
}
$a = new Foo;
$a->__clone();
?>
See also Directly calling `__clone is allowed <https://wiki.php.net/rfc/abstract_syntax_tree#directly_calling_clone_is_allowed>`_.
1.2.752.1. Suggestions¶
Use the clone operator to call the __clone magic method
1.2.752.2. Specs¶
Short name |
Php/DirectCallToClone |
Rulesets |
CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, All |
Exakat since |
1.4.8 |
PHP Version |
7.0+ |
Severity |
Critical |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.753. Unknown Directive Name¶
Unknown directives names used in the code.
The following list has directive mentioned in the code, that are not known from PHP or any extension. If this is due to a mistake, the directive must be fixed to be actually useful.
<?php
// non-existing directive
$reporting_error = ini_get('reporting_error');
$error_reporting = ini_get('error_reproting'); // Note the inversion
if (ini_set('dump_globals')) {
// doSomething()
}
// Correct directives
$error_reporting = ini_get('reporting_error');
if (ini_set('xdebug.dump_globals')) {
// doSomething()
}
?>
1.2.753.1. Specs¶
Short name |
Php/DirectiveName |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.754. Directives Usage¶
List of the directives mentioned in the code.
<?php
//accessing the configuration to change it
ini_set('timelimit', -1);
//accessing the configuration to check it
ini_get('safe_mode');
?>
1.2.754.1. Specs¶
Short name |
Php/DirectivesUsage |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.755. Dl() Usage¶
Dynamically load PHP extensions with dl().
<?php
// dynamically loading ext/vips
dl('vips.' . PHP_SHLIB_SUFFIX);
?>
See also dl.
1.2.755.1. Specs¶
Short name |
Php/DlUsage |
Rulesets |
|
Exakat since |
1.0.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.756. Don’t Pollute Global Space¶
Avoid creating definitions in the global name space.
The global namespace is the default namespace, where all functions, classes, constants, traits and interfaces live. The global namespace is also known as the root namespace.
In particular, PHP native classes usually live in that namespace. By creating functions in that namespace, the code may encounter naming conflict, when the PHP group decides to use a name that the code also uses. This already happened in PHP version 5.1.1, where a Date native class was introduced, and had to be disabled in the following minor version.
Nowadays, conflicts appear between components, which claim the same name.
See also Using namespaces: fallback to global function/constant.
1.2.756.1. Suggestions¶
Create a namespace for your code, and store your definition there.
1.2.756.2. Specs¶
Short name |
Php/DontPolluteGlobalSpace |
Rulesets |
|
Exakat since |
2.1.7 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.757. <?= Usage¶
Usage of the <?= tag, that echo’s directly the following content.
<?= $variable; ?>
1.2.757.1. Specs¶
Short name |
Php/EchoTagUsage |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.758. Ellipsis Usage¶
Usage of the ellipsis keyword. The keyword is three dots : … . It is also named variadic or splat operator.
It may be in function definitions, either in functioncalls.
… allows for packing or unpacking arguments into an array.
<?php
$args = [1, 2, 3];
foo(...$args);
// Identical to foo(1,2,3);
function bar(...$a) {
// Identical to : $a = func_get_args();
}
?>
See also PHP RFC: Syntax for variadic functions, PHP 5.6 and the Splat Operator, and Variable-length argument lists.
1.2.758.1. Specs¶
Short name |
Php/EllipsisUsage |
Rulesets |
Appinfo, CE, CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, All |
Exakat since |
0.8.4 |
PHP Version |
5.6+ |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.759. Empty List¶
Empty list() are not allowed anymore in PHP 7. There must be at least one variable in the list call.
<?php
//Not accepted since PHP 7.0
list() = array(1,2,3);
//Still valid PHP code
list(,$x) = array(1,2,3);
?>
1.2.759.1. Suggestions¶
Remove empty list() calls
1.2.759.2. Specs¶
Short name |
Php/EmptyList |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
7.0- |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.760. Enum Usage¶
PHP’s enumeration. Introduced in PHP 8.1.
<?php
enum X {
case A;
case B;
}
?>
1.2.760.1. Specs¶
Short name |
Php/EnumUsage |
Rulesets |
CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, CompatibilityPHP70, CompatibilityPHP71, CompatibilityPHP72, CompatibilityPHP73, CompatibilityPHP74, CompatibilityPHP80, All |
Exakat since |
2.2.2 |
PHP Version |
With PHP 8.1 and more recent |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Available in |
1.2.761. Error_Log() Usage¶
Usage of error_log() function. This leads to checking the configuration of
error_login the PHP configuration directives.
<?php
error_log(logging message\n);
?>
1.2.761.1. Specs¶
Short name |
Php/ErrorLogUsage |
Rulesets |
|
Exakat since |
0.10.0 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.762. Exponent Usage¶
Usage of the ** operator or **=, to make exponents.
<?php
$eight = 2 ** 3;
$sixteen = 4;
$sixteen \*\*\= 2;
?>
See also Arithmetic Operators.
1.2.762.1. Suggestions¶
Use the operator when no literal negative number is in the expression
1.2.762.2. Specs¶
Short name |
Php/ExponentUsage |
Rulesets |
CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, All |
Exakat since |
0.8.4 |
PHP Version |
5.6+ |
Severity |
Major |
Time To Fix |
Instant (5 mins) |
Precision |
Very high |
Available in |
1.2.763. Php/FailingAnalysis¶
1.2.763.1. Specs¶
Short name |
Php/FailingAnalysis |
Rulesets |
|
Exakat since |
1.2.8 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.764. $FILES full_path¶
A new index ‘full_path’ was added to the $_FILES to handle directory uploads. This was added in PHP 8.1, and is not available before.
<?php
// list uploaded files in a directory
print_r($_FILES['full_path']);
?>
See also ` <https://php.watch/versions/8.1/$_FILES-full-path>`_.
1.2.764.1. Specs¶
Short name |
Php/FilesFullPath |
Rulesets |
CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, CompatibilityPHP70, CompatibilityPHP71, CompatibilityPHP72, CompatibilityPHP73, CompatibilityPHP74, All |
Exakat since |
2.2.4 |
PHP Version |
With PHP 8.1 and older |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.765. Filter To add_slashes()¶
FILTER_SANITIZE_MAGIC_QUOTESis deprecated. In PHP 7.4, it should be replaced with addslashes()
According to the migration RDFC : ‘Magic quotes were deprecated all the way back in PHP 5.3 and later removed in PHP 5.4. The filter extension implements a sanitization filter that mimics this behavior of magic_quotes by calling addslashes() on the input in question.’
<?php
// Deprecated way to filter input
$var = filter_input($input, FILTER_SANITIZE_MAGIC_QUOTES);
// Alternative way to filter input
$var = addslashes($input);
?>
addslashes() used to filter data while building SQL queries, to prevent injections. Nowadays, prepared queries are a better option.
See also Deprecations for PHP 7.4.
1.2.765.1. Suggestions¶
Replace
FILTER_SANITIZE_MAGIC_QUOTESwith addslashes()Replace
FILTER_SANITIZE_MAGIC_QUOTESwith an adapted escaping system
1.2.765.2. Specs¶
Short name |
Php/FilterToAddSlashes |
Rulesets |
|
Exakat since |
1.9.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.766. Final Constant¶
Final modifier for class constants.
<?php
class MyClass {
final const X = 1; // This constant cannot be redefined
const Y = 2; // This constant might be redefined in a child
private const Z = 3; // This private, and can't be made final, because it is not available anyway
}
?>
See also https://www.php.net/manual/en/language.oop5.final.php and https://php.watch/versions/8.1/final-class-const.
1.2.766.1. Specs¶
Short name |
Php/FinalConstant |
Rulesets |
Appinfo, CompatibilityPHP70, CompatibilityPHP71, CompatibilityPHP72, CompatibilityPHP73, CompatibilityPHP74, CompatibilityPHP80, All |
Exakat since |
2.3.0 |
PHP Version |
With PHP 8.1 and more recent |
Severity |
Major |
Time To Fix |
Instant (5 mins) |
Precision |
Very high |
Available in |
1.2.767. Flexible Heredoc¶
Flexible syntax for Heredoc.
The new flexible syntax for heredoc and nowdoc enable the closing marker to be indented, and remove the new line requirement after the closing marker.
It was introduced in PHP 7.3.
<?php
// PHP 7.3 and newer
foo($a = <<<END
flexible syntax
with extra indentation
END);
// All PHP versions
$a = <<<END
Normal syntax
END;
?>
This syntax is backward incompatible : once adopted in the code, previous versions won’t compile it.
See also Heredoc and Flexible Heredoc and Nowdoc Syntaxes.
1.2.767.1. Specs¶
Short name |
Php/FlexibleHeredoc |
Rulesets |
CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, CompatibilityPHP70, CompatibilityPHP71, CompatibilityPHP72, All |
Exakat since |
1.2.9 |
PHP Version |
7.3+ |
Severity |
Critical |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.768. Wrong fopen() Mode¶
Wrong file opening for fopen().
fopen() has a few modes, as described in the documentation : ‘r’, ‘r+’, for reading; ‘w’, ‘w+’ for writing; ‘a’, ‘a+’ for appending; ‘x’, ‘x+’ for modifying; ‘c’, ‘c+’ for writing and locking, ‘t’ for text files and windows only. An optional ‘b’ may be used to make the fopen() call more portable and binary safe. Another optional ‘t’ may be used to make the fopen() call process automatically text input : this one should be avoided.
<?php
// open the file for reading, in binary mode
$fp = fopen('/tmp/php.txt', 'rb');
// New option e in PHP 7.0.16 and 7.1.2 (beware of compatibility)
$fp = fopen('/tmp/php.txt', 'rbe');
// Unknown option x
$fp = fopen('/tmp/php.txt', 'rbx');
?>
Any other values are not understood by PHP.
1.2.768.1. Suggestions¶
Check the docs, choose the right opening mode.
1.2.768.2. Specs¶
Short name |
Php/FopenMode |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.769. Foreach Don’t Change Pointer¶
foreach loops use their own internal cursor.
A foreach loop won’t change the internal pointer of the array, as it works on a copy of the source. Hence, applying array pointer’s functions such as current() or next() to the source array won’t have the same behavior in PHP 5 than PHP 7.
This only applies when a foreach() by reference is used.
<?php
$numbers = range(1, 10);
next($numbers);
foreach($numbers as &$number){
print $number;
print current($numbers).\n; // Always
}
?>
See also foreach no longer changes the internal array pointer and foreach.
1.2.769.1. Suggestions¶
Do not change the pointer on the source array while in the loop
1.2.769.2. Specs¶
Short name |
Php/ForeachDontChangePointer |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
7.0- |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.770. Foreach On Object¶
Foreach on object looks like a typo. This is particularly true when both object and member are variables.
Foreach on an object member is a legit PHP syntax, though it is very rare : blind variables rarely have to be securing in an object to be processed.
<?php
// This is the real thing
foreach($array as $o => $b) {
doSomething();
}
// Looks suspicious
foreach($array as $o -> $b) {
doSomething();
}
?>
1.2.770.1. Specs¶
Short name |
Php/ForeachObject |
Rulesets |
|
Exakat since |
1.1.6 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.771. Simple Global Variable¶
The global keyword should only be used with simple variables. Since PHP 7, it cannot be used with complex or dynamic structures.
<?php
// Forbidden in PHP 7
global $normalGlobal;
// Forbidden in PHP 7
global $$variable->global ;
// Tolerated in PHP 7
global ${$variable->global};
?>
1.2.771.1. Suggestions¶
Add curly braces so the syntax is compatibles PHP 5 and PHP 7
Remove this syntax, and access the variable through another way : argument, array, property.
1.2.771.2. Specs¶
Short name |
Php/GlobalWithoutSimpleVariable |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
7.0- |
Severity |
Critical |
Time To Fix |
Slow (1 hour) |
Precision |
Very high |
Available in |
1.2.772. $GLOBALS Or global¶
Usually, PHP projects make a choice between the global keyword, and the $GLOBALS variable. Sometimes, the project has no recommendations.
When your project use a vast majority of one of the convention, then the analyzer will report all remaining inconsistently cased constant.
<?php
global $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m;
// This access is inconsistent with the previous usage
$GLOBALS['a'] = 2;
?>
1.2.772.1. Specs¶
Short name |
Php/GlobalsVsGlobal |
Rulesets |
|
Exakat since |
0.9.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.773. Goto Names¶
List of all goto labels used in the code.
<?php
GOTO_NAME_1:
// reports the usage of GOTO_NAME_1
goto GOTO_NAME_1;
UNUSED_GOTO_NAME_1:
?>
1.2.773.1. Specs¶
Short name |
Php/Gotonames |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
Very high |
ClearPHP |
|
Available in |
1.2.774. Group Use Declaration¶
The group use declaration is used in the code.
<?php
// Adapted from the RFC documentation
// Pre PHP 7 code
use some\name_space\ClassA;
use some\name_space\ClassB;
use some\name_space\ClassC as C;
use function some\name_space\fn_a;
use function some\name_space\fn_b;
use function some\name_space\fn_c;
use const some\name_space\ConstA;
use const some\name_space\ConstB;
use const some\name_space\ConstC;
// PHP 7+ code
use some\name_space\{ClassA, ClassB, ClassC as C};
use function some\name_space\{fn_a, fn_b, fn_c};
use const some\name_space\{ConstA, ConstB, ConstC};
?>
See also Group Use Declaration RFC and Using namespaces: Aliasing/Importing.
1.2.774.1. Specs¶
Short name |
Php/GroupUseDeclaration |
Rulesets |
Appinfo, CE, CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, All |
Exakat since |
0.10.7 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.775. Group Use Trailing Comma¶
The usage of a final empty slot in array() was allowed with use statements. This works in PHP 7.2 and more recent.
Although this empty instruction is ignored at execution, this allows for clean presentation of code, and short diff when committing in a VCS.
<?php
// Valid in PHP 7.2 and more recent.
use a\b\{c,
d,
e,
f,
};
// This won't compile in 7.1 and older.
?>
See also Trailing Commas In List Syntax and Revisit trailing commas in function arguments.
1.2.775.1. Specs¶
Short name |
Php/GroupUseTrailingComma |
Rulesets |
CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, CompatibilityPHP70, CompatibilityPHP71, All |
Exakat since |
0.12.3 |
PHP Version |
7.2+ |
Severity |
Major |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.776. __halt_compiler¶
__halt_compiler() usage.
<?php
// open this file
$fp = fopen(__FILE__, 'r');
// seek file pointer to data
fseek($fp, __COMPILER_HALT_OFFSET__);
// and output it
var_dump(stream_get_contents($fp));
// the end of the script execution
__halt_compiler(); the installation data (eg. tar, gz, PHP, etc.)
?>
1.2.776.1. Specs¶
Short name |
Php/Haltcompiler |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.777. Hash Algorithms¶
There is a long but limited list of hashing algorithm available to PHP. The one found doesn’t seem to be existing.
<?php
// This hash has existed in PHP. Check with hash_algos() if it is available on your system.
echo hash('ripmed160', 'The quick brown fox jumped over the lazy dog.');
// This hash doesn't exist
echo hash('ripemd160', 'The quick brown fox jumped over the lazy dog.');
?>
See also hash_algos.
1.2.777.1. Suggestions¶
Use a hash algorithm that is available on several PHP versions
Fix the name of the hash algorithm
1.2.777.2. Specs¶
Short name |
Php/HashAlgos |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.778. Hash Algorithms Incompatible With PHP 5.3¶
List of hash algorithms incompatible with PHP 5.3.
<?php
// Compatible only with 5.3 and more recent
echo hash('md2', 'The quick brown fox jumped over the lazy dog.');
// Always compatible
echo hash('ripemd320', 'The quick brown fox jumped over the lazy dog.');
?>
See also hash_algos.
1.2.778.1. Specs¶
Short name |
Php/HashAlgos53 |
Rulesets |
CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, CompatibilityPHP70, CompatibilityPHP71, CompatibilityPHP72, All |
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.779. Hash Algorithms Incompatible With PHP 5.4/5.5¶
List of hash algorithms incompatible with PHP 5.4 and 5.5.
<?php
// Compatible only with 5.4 and more recent
echo hash('fnv132', 'The quick brown fox jumped over the lazy dog.');
// Always compatible
echo hash('ripemd320', 'The quick brown fox jumped over the lazy dog.');
?>
See also hash_algos.
1.2.779.1. Specs¶
Short name |
Php/HashAlgos54 |
Rulesets |
CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, CompatibilityPHP70, CompatibilityPHP71, CompatibilityPHP72, All |
Exakat since |
0.8.4 |
PHP Version |
5.4- |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.780. Hash Algorithms Incompatible With PHP 7.1-¶
List of hash algorithms incompatible with PHP 7.1 and more recent. At the moment of writing, this is compatible up to 7.3.
The hash algorithms were introduced in PHP 7.1.
<?php
// Compatible only with 7.1 and more recent
echo hash('sha512/224', 'The quick brown fox jumped over the lazy dog.');
// Always compatible
echo hash('ripemd320', 'The quick brown fox jumped over the lazy dog.');
?>
See also hash_algos.
1.2.780.1. Specs¶
Short name |
Php/HashAlgos71 |
Rulesets |
CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, CompatibilityPHP70, All |
Exakat since |
1.3.4 |
PHP Version |
7.1- |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.781. Hash Algorithms Incompatible With PHP 7.4-¶
List of hash algorithms incompatible with PHP 7.3 and older recent. At the moment of writing, this is compatible up to 7.4s.
The hash algorithms were introduced in PHP 7.4s.
<?php
// Compatible only with 7.1 and more recent
echo hash('crc32cs', 'The quick brown fox jumped over the lazy dog.');
// Always compatible
echo hash('ripemd320', 'The quick brown fox jumped over the lazy dog.');
?>
See also hash_algos.
1.2.781.1. Specs¶
Short name |
Php/HashAlgos74 |
Rulesets |
|
Exakat since |
1.3.4 |
PHP Version |
7.4- |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.782. Hash Will Use Objects¶
The ext/hash extension used resources, and is being upgraded to use resources.
<?php
// Post 7.2 code
$hash = hash_init('sha256');
if (!is_object($hash)) {
trigger_error('error');
}
hash_update($hash, $message);
// Pre-7.2 code
$hash = hash_init('md5');
if (!is_resource($hash)) {
trigger_error('error');
}
hash_update($hash, $message);
?>
See also Move ext/hash from resources to objects.
1.2.782.1. Specs¶
Short name |
Php/HashUsesObjects |
Rulesets |
|
Exakat since |
1.0.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.783. idn_to_ascii() New Default¶
The default parameter value of idn_to_ascii() and idn_to_utf8() is now INTL_IDNA_VARIANT_UTS46 instead of the deprecated INTL_IDNA_VARIANT_2003.
<?php
echo idn_to_ascii('täst.de');
?>
See also idn_to_ascii, idn_to_utf8 and Unicode IDNA Compatibility Processing.
1.2.783.1. Suggestions¶
Explicitely add the second parameter to the idn_to_ascii() and idn_to_utf8() functions.
1.2.783.2. Specs¶
Short name |
Php/IdnUts46 |
Rulesets |
|
Exakat since |
2.2.3 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Available in |
1.2.784. Implode One Arg¶
implode() may be called with one arg. It is recommended to avoid it.
Using two arguments makes it less surprising to new comers, and consistent with explode() syntax.
<?php
$array = range('a', 'c');
// empty string is the glue
print implode('', $array);
// only the array : PHP uses the empty string as glue.
// Avoid this
print implode($array);
?>
See also implode.
1.2.784.1. Suggestions¶
Add an empty string as first argument
1.2.784.2. Specs¶
Short name |
Php/ImplodeOneArg |
Rulesets |
|
Exakat since |
1.7.7 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Available in |
1.2.785. Incoming Values¶
The names of the variables that are passed via the superglobals.
<?php
$x = $_GET['y']; // y is the incoming variable
?>
1.2.785.1. Specs¶
Short name |
Php/IncomingValues |
Rulesets |
|
Exakat since |
1.7.7 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.786. Incoming Variables¶
Incoming names, used across the application.
Incoming variables are first-level index in $_POST, $_GET, $_COOKIE, $_REQUEST and $_FILE;
$_SESSION and $_ENV are not reported as incoming data, as they are not supposed to be manipulated by normal user.
Dynamic names are not reported too.
<?php
$name = $_GET['name'];
$cookie = $_COOKIE['cookie'];
// 'archive' is the incoming variable, not 'file_name'
$file_name = $_FILE['archive']['file_name'];
// This is not reported, because it is from $_ENV.
$db_pass = $_ENV['DB_PASS'];
// This is not reported, because it is dynamic
$x = 'userId';
$userId = $_GET[$x];
?>
1.2.786.1. Specs¶
Short name |
Php/IncomingVariables |
Rulesets |
|
Exakat since |
2.2.3 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Available in |
1.2.787. Incompilable Files¶
Files that cannot be compiled, and, as such, be run by PHP. Scripts are linted against various versions of PHP.
This is usually undesirable, as all code must compile before being executed. It may be that such files are not compilable because they are not yet ready for an upcoming PHP version.
<?php
// Can't compile this : Print only accepts one argument
print $a, $b, $c;
?>
Code that is not compilable with older PHP versions means that the code is breaking backward compatibility : good or bad is project decision.
When the code is used as a template for PHP code generation, for example at installation time, it is recommended to use a distinct file extension, so as to distinguish them from actual PHP code.
1.2.787.1. Suggestions¶
If this file is a template for PHP code, change the extension to something else than .php
Fix the syntax so it works with various versions of PHP
1.2.787.2. Specs¶
Short name |
Php/Incompilable |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Critical |
Time To Fix |
Slow (1 hour) |
Precision |
High |
ClearPHP |
|
Examples |
|
Available in |
1.2.788. Numeric Literal Separator¶
Integer and floats may be written with internal underscores. This way, it is possible to separate large number into smaller groups, and make them more readable.
Numeric Literal Separators were introduced in PHP 7.4 and are not backward compatible.
<?php
$a = 1_000_000_000; // A billion
$a = 1000000000; // A billion too...
$b = 107_925_284.88; // 6 light minute to kilometers = 107925284.88 kilometers
$b = 107925284.88; // Same as above
?>
See also and PHP RFC: Numeric Literal Separator.
1.2.788.1. Specs¶
Short name |
Php/IntegerSeparatorUsage |
Rulesets |
|
Exakat since |
1.9.0 |
PHP Version |
With PHP 7.4 and more recent |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Available in |
1.2.789. Wrong Parameter Type¶
The expected parameter is not of the correct type. Check PHP documentation to know which is the right format to be used.
<?php
// substr() shouldn't work on integers.
// the first argument is first converted to string, and it is 123456.
echo substr(123456, 0, 4); // display 1234
// substr() shouldn't work on boolean
// the first argument is first converted to string, and it is 1, and not t
echo substr(true, 0, 1); // displays 1
// substr() works correctly on strings.
echo substr(123456, 0, 4);
?>
1.2.789.1. Specs¶
Short name |
Php/InternalParameterType |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.790. Is_A() With String¶
When using is_a() with a string as first argument, the third argument is compulsory.
<?php
// is_a() works with string as first argument, when the third argument is 'true'
if (is_s('A', 'B', true)) {}
// is_a() works with object as first argument
if (is_s(new A, 'A')) {}
?>
1.2.790.1. Suggestions¶
Add the third argument, and set it to true
Use an object as a first argument
See also and is_a.
1.2.790.2. Specs¶
Short name |
Php/IsAWithString |
Rulesets |
|
Exakat since |
1.9.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.791. Manipulates INF¶
<?php
// pow returns INF, as it is equivalent to 1 / 0 ^ 2
$a = pow(0,-2); //
// exp returns an actual value, but won't be able to represent it as a float
$a = exp(PHP_INT_MAX);
// 0 ^ -1 is like 1 / 0 but returns INF.
$a = pow(0, -1);
var_dump(is_infinite($a));
// This yields a Division by zero exception
$a = 1 / 0;
?>
See also Math predefined constants.
1.2.791.1. Specs¶
Short name |
Php/IsINF |
Rulesets |
|
Exakat since |
0.10.6 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.792. Manipulates NaN¶
This code handles
Not-a-Numbersituations.Not-a-Number, also calledNaN, happens when a calculation can’t return an actual float.
<?php
// acos returns a float, unless it is not possible.
$a = acos(8);
var_dump(is_nan($a));
?>
See also Floats.
1.2.792.1. Specs¶
Short name |
Php/IsNAN |
Rulesets |
|
Exakat since |
0.10.6 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Available in |
1.2.793. Use === null¶
It is faster to use === null instead of is_null().
<?php
// Operator === is fast
if ($a === null) {
}
// Function call is slow
if (is_null($a)) {
}
?>
1.2.793.1. Suggestions¶
Use === comparison
1.2.793.2. Specs¶
Short name |
Php/IsnullVsEqualNull |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
ClearPHP |
|
Available in |
1.2.794. Isset Multiple Arguments¶
isset() may be used with multiple arguments and acts as a AND.
<?php
// isset without and
if (isset($a, $b, $c)) {
// doSomething()
}
// isset with and
if (isset($a) && isset($b) && isset($c)) {
// doSomething()
}
?>
See also Isset <http://www.php.net/`isset>`_.
1.2.794.1. Suggestions¶
Merge all isset() calls into one
1.2.794.2. Specs¶
Short name |
Php/IssetMultipleArgs |
Rulesets |
|
Exakat since |
0.12.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.795. JsonSerialize() Mixed Return Type¶
A mixed return type was added to the jsonSerialize() of the JsonSerialize PHP interface.
In PHP 8.1, the mixed return type is now enforced, and a deprecated notice is displayed.
<?php
class MyJsonSerialize implements jsonserialize {
function jsonserialize() : int {}
}
?>
1.2.795.1. Suggestions¶
Add the mixed returntype to all implementation of the jsonSerialize method
Add the #[ReturnTypeWillChange] attribute to the method
1.2.795.2. Specs¶
Short name |
Php/JsonSerializeReturnType |
Rulesets |
Analyze, CompatibilityPHP81, Deprecated, LintButWontExec, All |
Exakat since |
2.3.0 |
PHP Version |
With PHP 8.0 and more recent |
PHP deprecated |
8.1 |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Available in |
1.2.796. Labels¶
List of all labels used in the code.
<?php
// A is label.
goto A:
A:
// A label may be used by several gotos.
goto A:
?>
1.2.796.1. Specs¶
Short name |
Php/Labelnames |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.797. Logical Operators Favorite¶
PHP has two sets of logical operators : letters (and, or, xor) and chars (&&, ||, ^).
The analyzed code has less than 10% of one of the two sets : for consistency reasons, it is recommended to make them all the same.
Warning : the two sets of operators have different precedence levels. Using and or && is not exactly the same, especially and not only, when assigning the results to a variable.
<?php
$a1 = $b and $c;
$a1 = $b and $c;
$a1 = $b and $c;
$a1 = $b or $c;
$a1 = $b OR $c;
$a1 = $b and $c;
$a1 = $b and $c;
$a1 = $b and $c;
$a1 = $b or $c;
$a1 = $b OR $c;
$a1 = $b ^ $c;
?>
Using and or && are also the target of other analysis.
See also Logical Operators and Operators Precedence.
1.2.797.1. Suggestions¶
Pick a favorite, and enforce it
1.2.797.2. Specs¶
Short name |
Php/LetterCharsLogicalFavorite |
Rulesets |
|
Exakat since |
0.12.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.798. List Short Syntax¶
Usage of short syntax version of list().
<?php
// PHP 7.1 short list syntax
// PHP 7.1 may also use key => value structures with list
[$a, $b, $c] = ['2', 3, '4'];
// PHP 7.0 list syntax
list($a, $b, $c) = ['2', 3, '4'];
?>
1.2.798.1. Specs¶
Short name |
Php/ListShortSyntax |
Rulesets |
Appinfo, CE, CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, CompatibilityPHP70, All |
Exakat since |
0.8.4 |
PHP Version |
7.1+ |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.799. List With Appends¶
List() behavior has changed in PHP 7.0 and it has impact on the indexing when list is used with the [] operator.
<?php
$x = array();
list($x[], $x[], $x[]) = [1, 2, 3];
print_r($x);
?>
In PHP 7.0, results are ::
Array
(
[0] => 1
[1] => 2
[2] => 3
)
In PHP 5.6, results are ::
Array
(
[0] => 3
[1] => 2
[2] => 1
)
1.2.799.1. Suggestions¶
Refactor code to avoid using append in a list() call
1.2.799.2. Specs¶
Short name |
Php/ListWithAppends |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.800. List With Keys¶
Setting keys when using list() is a PHP 7.1 feature.
<?php
// PHP 7.1 and later only
list('a' => $a, 'b' => $b) = ['b' => 1, 'c' => 2, 'a' => 3];
?>
1.2.800.1. Specs¶
Short name |
Php/ListWithKeys |
Rulesets |
Appinfo, CE, CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, CompatibilityPHP70, All |
Exakat since |
0.8.4 |
PHP Version |
7.1+ |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.801. List With Reference¶
Support for references in list calls is not backward compatible with older versions of PHP. The support was introduced in PHP 7.3.
<?php
$array = [1,2,3];
[$c, &$d, $e] = $a;
$d++;
$c++;
print_r($array);
/*
displays
Array
(
[0] => 1 // Not a reference to $c, unchanged
[1] => 3 // Reference from $d
[2] => 3
)
*/
?>
See also list() Reference Assignment.
1.2.801.1. Suggestions¶
Avoid using references in list for backward compatibility
1.2.801.2. Specs¶
Short name |
Php/ListWithReference |
Rulesets |
CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, CompatibilityPHP70, CompatibilityPHP71, CompatibilityPHP72, All |
Exakat since |
1.1.6 |
PHP Version |
7.3+ |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.802. Logical Should Use Symbolic Operators¶
Logical operators come in two flavors : and / &&, || / or, ^ / xor. However, they are not exchangeable, as && and and have different precedence.
<?php
// Avoid lettered operator, as they have lower priority than expected
$a = $b and $c;
// $a === 3 because equivalent to ($a = $b) and $c;
// safe way to write the above :
$a = ($b and $c);
$a = $b && $c;
// $a === 1
?>
It is recommended to use the symbol operators, rather than the letter ones.
See also Logical Operators.
1.2.802.1. Suggestions¶
Change the letter operators to the symbol one : and => &&, or => ||, xor => ^. Review the new expressions as processing order may have changed.
Add parenthesis to make sure that the order is the expected one
1.2.802.2. Specs¶
Short name |
Php/LogicalInLetters |
Rulesets |
Analyze, CE, CI-checks, php-cs-fixable, Suggestions, Top10, All |
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
ClearPHP |
|
Examples |
|
Available in |
1.2.803. Methodcall On New¶
It is possible to call a method right at object instantiation.
This syntax was added in PHP 5.4+. Before, this was not possible : the object had to be stored in a variable first.
<?php
// Data is collected
$data = data_source();
// Data is saved, but won't be reused from this databaseRow object. It may be ignored.
$result = (new databaseRow($data))->save();
// The actual result of the save() is collected and tested.
if ($result !== true) {
processSaveError($data);
}
?>
This syntax is interesting when the object is not reused, and may be discarded
1.2.803.1. Specs¶
Short name |
Php/MethodCallOnNew |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
5.4+ |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.804. PHP Bugfixes¶
This is the list of features, used in the code, that also received a bug fix in recent PHP versions.
1.2.804.1. Specs¶
Short name |
Php/MiddleVersion |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.805. Missing __isset() Method¶
<?php
class foo {
function __get($name) { return 'foo'; }
// No __isset method
}
// Return TRUE, until __isset() exists
var_dump(
empty((new foo)->bar);
);
?>
See also When empty is not empty.
1.2.805.1. Suggestions¶
Implement __isset() method when using empty on magic properties
1.2.805.2. Specs¶
Short name |
Php/MissingMagicIsset |
Rulesets |
|
Exakat since |
2.2.0 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Medium |
Available in |
1.2.806. Possible Missing Subpattern¶
When capturing subpatterns are the last ones in a regex, PHP doesn’t fill their spot in the resulting array. This leads to a possible missing index in the result array.
<?php
// displays a partial array, from 0 to 1
preg_match('/(a)(b)?/', 'adc', $r);
print_r($r);
/*
Array
(
[0] => a
[1] => a
)
*/
// displays a full array, from 0 to 2
preg_match('/(a)(b)?/', 'abc', $r);
print_r($r);
/*
Array
(
[0] => ab
[1] => a
[2] => b
)
*/
// double 'b' when it is found
print preg_replace(',^a(b)?,', './\$1\$1', 'abc'); // prints ./abbc
print preg_replace(',^a(b)?,', './\$1\$1', 'adc'); // prints ./dc
?>
?>
The same applies to preg_replace() : the pattern may match the string, but no value is available is the corresponding sub-pattern.
In PHP 7.4, a new option was added : PREG_UNMATCHED_AS_NULL, which always provides a value for the subpatterns.
See also Bug #50887 preg_match , last optional sub-patterns ignored when empty and Bug #73948 Preg_match_all should return NULLs on trailing optional capture groups..
1.2.806.1. Suggestions¶
Add an always capturing subpatterns after the last ?
Move the ? inside the parenthesis, so the parenthesis is always on, but the content may be empty
Add a test on the last index of the resulting array, to ensure it is available when needed
Use the PREG_UNMATCHED_AS_NULL option (PHP 7.4+)
1.2.806.2. Specs¶
Short name |
Php/MissingSubpattern |
Rulesets |
|
Exakat since |
1.6.1 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.807. Multiple Declaration Of Strict_types¶
At least two declare() commands are declaring strict_types in one file. Only one is sufficient, and should be the first expression in the file.
Indeed, any strict_types set to 1 will have the final word. Setting strict_types to 0 will not revert the configuration, wherever is this call made.
<?php
declare(strict_types=1);
declare(strict_types=1);
// rest of the code
?>
See also Declare.
1.2.807.1. Suggestions¶
Just remove all but one of them.
1.2.807.2. Specs¶
Short name |
Php/MultipleDeclareStrict |
Rulesets |
|
Exakat since |
2.1.8 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Available in |
1.2.808. Must Call Parent Constructor¶
Some PHP native classes require a call to parent::__construct() to be stable.
As of PHP 7.3, two classes currently need that call : SplTempFileObject and SplFileObject.
The error is only emitted if the class is instantiated, and a parent class is called.
<?php
class mySplFileObject extends \SplFileObject {
public function __construct() {
// Forgottent call to parent::__construct()
}
}
(new mySplFileObject())->passthru();
?>
See also Why, php? WHY???.
1.2.808.1. Suggestions¶
Add a call to the parent’s constructor
Remove the extension of the parent class
1.2.808.2. Specs¶
Short name |
Php/MustCallParentConstructor |
Rulesets |
|
Exakat since |
1.4.1 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.809. PHP Native Class Type Compatibility¶
PHP eventually enforces the method compatibilities with native classes en interfaces.
This means that classes that extends those native PHP classes or interfaces must declare compatible types. They can’t skip the type like it was the case before.
<?php
class a extends RecursiveFilterIterator {
// fully declared method
function hasChildren(): bool {
return true;
}
// key() returns mixed. Omitting the type used to be quiet
function key() {}
// #[\ReturnTypeWillChange] is taken into account
}
?>
This is needed for compatibility with PHP 8.1. This is probably good for older versions too, although invisible.
The attribute ReturnTypeWillChange is taken into account. Note that it is not detected when auditing with PHP < 8.0, so it won’t have effect until this version. The attribute was declared in PHP 8.1, though it is also taken into account when auditing with PHP 8.0.
1.2.809.1. Suggestions¶
Make sure the methods are compatible or identical to the parent’s method signature.
1.2.809.2. Specs¶
Short name |
Php/NativeClassTypeCompatibility |
Rulesets |
|
Exakat since |
2.2.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.810. Nested Ternary Without Parenthesis¶
It is not allowed to nest ternary operator within itself, without parenthesis. This has been implemented in PHP 7.4.
The reason behind this feature is to keep the code expressive. See the Warning message for more explanations
<?php
$a ? 1 : ($b ? 2 : 3);
// Still valid, as not ambiguous
$a ? $b ? 1 : 2 : 3;
// Produces a warning
//Unparenthesized `a ? b : c ? d : e` is deprecated. Use either `(a ? b : c) ? d : e` or `a ? b : (c ? d : e)`
$a ? 1 : $b ? 2 : 3;
?>
See also PHP RFC: Deprecate left-associative ternary operator.
1.2.810.1. Suggestions¶
Add parenthesis to nested ternary calls
1.2.810.2. Specs¶
Short name |
Php/NestedTernaryWithoutParenthesis |
Rulesets |
|
Exakat since |
1.9.4 |
PHP Version |
7.4- |
PHP deprecated |
7.4 |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.811. Never Typehint Usage¶
Never is a typehint, which characterize methods that never return a value. It will either terminate the execution or throw an exception.
<?php
function redirect(string $url): never {
header('Location: ' . $url);
exit();
}
?>
See also The “never” Return Type for PHP.
1.2.811.1. Specs¶
Short name |
Php/NeverTypehintUsage |
Rulesets |
Appinfo, CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, CompatibilityPHP70, CompatibilityPHP71, CompatibilityPHP72, CompatibilityPHP73, CompatibilityPHP74, CompatibilityPHP80, All |
Exakat since |
2.3.0 |
PHP Version |
With PHP 8.1 and more recent |
Severity |
Major |
Time To Fix |
Instant (5 mins) |
Precision |
Very high |
Available in |
1.2.812. ** For Exponent¶
The operator
**calculates exponents, also known as power.
Use it instead of the slower function pow(). This operator was introduced in PHP 5.6.
<?php
$cube = pow(2, 3); // 8
$cubeInPHP56 = 2 ** 3; // 8
?>
Be aware the the ‘-‘ operator has lower priority than the ** operator : this leads to the following confusing result.
<?php
echo -3 ** 2;
// displays -9, instead of 9
?>
This is due to the parser that processes separately - and the following number. Since ** has priority, the power operation happens first.
Being an operator, ** is faster than pow(). This is a microoptimisation.
See also Arithmetic Operators.
1.2.812.1. Suggestions¶
Use the
**operatorFor powers of 2, use the bitshift operators
For literal powers of 2, consider using the
0xFFFFFFFFFsyntax.
1.2.812.2. Specs¶
Short name |
Php/NewExponent |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
5.6+ |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Examples |
|
Available in |
1.2.813. Do Not Cast To Int¶
Use functions like floor(), round() or ceil() : they use an explicit method for rounding, that helps keeping the side effects under control.
<?php
// echoes 7!
echo (int) ( (0.1 + 0.7) * 10 );
?>
See the warning on the docs about Integers.
1.2.813.1. Specs¶
Short name |
Php/NoCastToInt |
Rulesets |
none |
Exakat since |
0.10.6 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.814. No Class In Global¶
Avoid defining structures in Global namespace. Always prefer using a namespace. This will come handy later, either when publishing the code, or when importing a library, or even if PHP reclaims that name.
<?php
// Code prepared for later
namespace Foo {
class Bar {}
}
// Code that may conflict with other names.
namespace {
class Bar {}
}
?>
1.2.814.1. Suggestions¶
Use a specific namespace for your classes
1.2.814.2. Specs¶
Short name |
Php/NoClassInGlobal |
Rulesets |
|
Exakat since |
0.10.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Examples |
|
Available in |
1.2.815. No List With String¶
<?php
$x = 'abc';
list($a, $b, $c) = $x;
//list($a, $b, $c) = 'abc'; Never works
print $c;
// PHP 5.6- displays 'c'
// PHP 7.0+ displays nothing
?>
See also PHP 7.0 Backward incompatible changes : list() can no longer unpack string variables .
1.2.815.1. Suggestions¶
Use str_split() to break a string into bytes
Use substr() or $string[$offset] syntax to access specific bytes in the string
1.2.815.2. Specs¶
Short name |
Php/NoListWithString |
Rulesets |
CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, All |
Exakat since |
0.8.4 |
PHP Version |
7.0- |
Severity |
Major |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.816. No More Curly Arrays¶
Only use square brackets to access array elements. The usage of curly brackets for array access is deprecated since PHP 7.4.
<?php
$array = [1,2,3];
// always valid
echo $array[1];
// deprecated in PHP 7.4
echo $array{1};
?>
See also Deprecate curly brace syntax and Deprecate curly brace syntax for accessing array elements and string offsets.
1.2.816.1. Suggestions¶
Always use square brackets to access particular index in an array
1.2.816.2. Specs¶
Short name |
Php/NoMoreCurlyArrays |
Rulesets |
|
Exakat since |
1.9.2 |
PHP Version |
8.0- |
PHP deprecated |
7.4 |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Available in |
1.2.817. No Null For Native PHP Functions¶
Null is not acceptable anymore as an argument, for PHP native functions that require a non-nullable argument.
Until PHP 8.1, it was magically turned into an empty string.
<?php
$haystack = 'abc';
// $needle was omitted...
echo strpos($haystack, $needle);
?>
See also and PHP RFC: Deprecate passing null to non-nullable arguments of internal functions.
1.2.817.1. Specs¶
Short name |
Php/NoNullForNative |
Rulesets |
|
Exakat since |
2.2.5 |
PHP Version |
With PHP 8.1 and more recent |
PHP deprecated |
8.1 |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.818. No Reference For Static Property¶
Static properties used to behave independently when set to a reference value. This was fixed in PHP 7.3.
According to the PHP 7.3 changelog :
In PHP, static properties are shared between inheriting classes, unless the static property is explicitly overridden in a child class. However, due to an implementation artifact it was possible to separate the static properties by assigning a reference. This loophole has been fixed.
<?php
class Test {
public static $x = 0;
}
class Test2 extends Test { }
Test2::$x = &$x;
$x = 1;
var_dump(Test::$x, Test2::$x);
// Previously: int(0), int(1)
// Now: int(1), int(1)
?>
See also PHP 7.3 UPGRADE NOTES.
1.2.818.1. Specs¶
Short name |
Php/NoReferenceForStaticProperty |
Rulesets |
CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, CompatibilityPHP70, CompatibilityPHP71, CompatibilityPHP72, All |
Exakat since |
1.4.9 |
PHP Version |
7.3- |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
Medium |
Available in |
1.2.819. No Reference For Ternary¶
The ternary operator and the null coalescing operator are both expressions that only return values, and not a variable.
This means that any provided reference will be turned into its value. While this is usually invisible, it will raise a warning when a reference is expected. This is the case with methods returning a reference.
A PHP notice is generated when using a ternary operator or the null coalesce operator : Only variable references should be returned by reference. The notice is also emitted when returning objects.
This applies to methods, functions and closures.
<?php
// This works
function &foo($a, $b) {
if ($a === 1) {
return $b;
} else {
return $a;
}
}
// This raises a warning, as the operator returns a value
function &foo($a, $b) { return $a === 1 ? $b : $a; }
?>
See also Null Coalescing Operator, Ternary Operator.
1.2.819.1. Suggestions¶
Drop the reference at assignation time
Drop the reference in the argument definition
Drop the reference in the function return definition
1.2.819.2. Specs¶
Short name |
Php/NoReferenceForTernary |
Rulesets |
|
Exakat since |
1.0.8 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Examples |
|
Available in |
1.2.820. No Return For Generator¶
Return is not allowed in generator. In PHP versions older than 5.6 and older, they yield a fatal Error.
<?php
function generatorWithReturn() {
yield 1;
return 2;
}
?>
See also Generators overview.
1.2.820.1. Specs¶
Short name |
Php/NoReturnForGenerator |
Rulesets |
CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, All |
Exakat since |
1.4.9 |
PHP Version |
7.0+ |
Severity |
Critical |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.821. No String With Append¶
PHP 7 doesn’t allow the usage of [] with strings. [] is an array-only operator.
<?php
$string = 'abc';
// Not possible in PHP 7
$string[] = 'd';
?>
This was possible in PHP 5, but is now forbidden in PHP 7.
1.2.821.1. Suggestions¶
Use the concatenation operator
.to append strings.Use the concatenation short assignement
.=to append strings.
1.2.821.2. Specs¶
Short name |
Php/NoStringWithAppend |
Rulesets |
CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, All |
Exakat since |
0.8.4 |
PHP Version |
7.0+ |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.822. No Substr Minus One¶
Negative index were introduced in PHP 7.1. This syntax is not compatible with PHP 7.0 and older.
<?php
$string = 'abc';
echo $string[-1]; // c
echo $string[1]; // a
?>
See also Generalize support of negative string offsets.
1.2.822.1. Suggestions¶
Use the -1 index in a string, instead of a call to substr()
1.2.822.2. Specs¶
Short name |
Php/NoSubstrMinusOne |
Rulesets |
CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, CompatibilityPHP70, All |
Exakat since |
0.12.5 |
PHP Version |
7.1+ |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Available in |
1.2.823. Not A Scalar Type¶
intis the actual PHP scalar type, notinteger.
PHP 7 introduced several scalar types, in particular int, bool and float. Those three types are easily mistaken with integer, boolean, real and double.
Unless those classes actually exists, PHP emits some strange error messages.
<?php
// This expects a scalar of type 'integer'
function foo(int $i) {}
// This expects a object of class 'integer'
function abr(integer $i) {}
?>
Thanks to Benoit Viguier for the original idea for this analysis.
See also Type declarations.
1.2.823.1. Suggestions¶
Do not use
intas a class name, an interface name or a trait name.
1.2.823.2. Specs¶
Short name |
Php/NotScalarType |
Rulesets |
|
Exakat since |
1.0.7 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Instant (5 mins) |
Precision |
Very high |
Available in |
1.2.824. Only Container For Reference¶
When a PHP function requires an argument to be a reference, it cannot be called with a literal value.
The call must be made with a variable, or any assimilated data container : array, property or static property.
<?php
// This is not possible
preg_match('/a/', $string, []);
// This is working
preg_match('/a/', $string, $r);
?>
See also Passing arguments by reference.
1.2.824.1. Suggestions¶
Put the literal value in a variable before calling the function.
Omit the arguments, when it won’t be used.
1.2.824.2. Specs¶
Short name |
Php/OnlyVariableForReference |
Rulesets |
|
Exakat since |
2.2.0 |
PHP Version |
All |
Severity |
Critical |
Time To Fix |
Quick (30 mins) |
Precision |
Medium |
Available in |
1.2.825. Openssl Encrypt Default Algorithm Change¶
openssl_pkcs7_encrypt() and openssl_cms_encrypt() will now default to using AES-128-CBC rather than RC2-40. The RC2-40 cipher is considered insecure and not enabled by default in OpenSSL 3.
This means that the default argument of OPENSSL_CIPHER_RC2_40 is replaced by OPENSSL_CIPHER_AES_128_CBC.
<?php
// extracted from the PHP documentation
// encrypt it
if (openssl_pkcs7_encrypt(msg.txt, enc.txt, $key,
array(To => nighthawk@example.com, // keyed syntax
From: HQ <hq@example.com>, // indexed syntax
Subject => Eyes only))) {
// message encrypted - send it!
exec(ini_get(sendmail_path) . < enc.txt);
}
?>
1.2.825.1. Suggestions¶
Explicitely set the 5th and 6th argument of the functioncalls to avoid a disruption.
Update the target service to handle the new cipher algorithm.
1.2.825.2. Specs¶
Short name |
Php/OpensslEncryptAlgoChange |
Rulesets |
|
Exakat since |
2.2.3 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Unknown |
Available in |
1.2.826. PHP Overridden Function¶
It is possible to declare and use PHP native function in a namespace.
Within the declaration namespace, it is easy to confuse the local version and the global version, unless the function has been prefixed with \.
<?php
namespace A {
use function A\dirname as split;
function dirname($a, $b) { return __FUNCTION__; }
echo dirname('/a/b/c');
echo split('a', 'b');
echo \dirname('/a/b/c');
}
?>
When a piece of code use overridden function, any newcomer may be confused by the usage of classic PHP native function in surprising situations.
It is recommended to avoid redeclare PHP native function in namespaces.
1.2.826.1. Suggestions¶
Change the name of the function, in its declaration and usage.
1.2.826.2. Specs¶
Short name |
Php/OveriddenFunction |
Rulesets |
|
Exakat since |
1.7.6 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.827. PHP 7.0 Scalar Typehints¶
New scalar typehints were introduced :
bool,int,float,string.
They cannot be used before PHP 7.0, and will be confused with classes or interfaces.
<?php
function foo(string $name) {
print Hello $name;
}
foo(Damien);
// display 'Hello Damien'
foo(33);
// displays an error
?>
See also Scalar type declarations, and PHP 7 SCALAR TYPE DECLARATIONS.
1.2.827.1. Specs¶
Short name |
Php/PHP70scalartypehints |
Rulesets |
CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, All |
Exakat since |
1.3.5 |
PHP Version |
7.0+ |
Severity |
Critical |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.828. PHP 7.1 Scalar Typehints¶
A new scalar typehint was introduced : iterable.
It can’t be used before PHP 7.1, and will be confused with classes or interfaces.
<?php
function foo(iterable $iterable) {
foreach ($iterable as $value) {
echo $value.PHP_EOL;
}
}
foo(range(1,20));
// works with array
foo(new ArrayIterator([1, 2, 3]));
// works with an iterator
foo((function () { yield 1; })() );
// works with a generator
?>
See also iterable pseudo-type, and The iterable Pseudo-Type.
1.2.828.1. Specs¶
Short name |
Php/PHP71scalartypehints |
Rulesets |
CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, CompatibilityPHP70, All |
Exakat since |
1.3.5 |
PHP Version |
7.1+ |
Severity |
Critical |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.829. PHP 7.2 Scalar Typehints¶
A new scalar typehint was introduced : object.
It can’t be used before PHP 7.2, and will be confused with classes or interfaces.
<?php
function test(object $obj) : object
{
return new SplQueue();
}
test(new StdClass());
?>
See also New object type, and PHP 7.2 and Object Typehint.
1.2.829.1. Specs¶
Short name |
Php/PHP72scalartypehints |
Rulesets |
CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, CompatibilityPHP70, CompatibilityPHP71, All |
Exakat since |
1.3.5 |
PHP Version |
7.2+ |
Severity |
Critical |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.830. PHP 7.3 Last Empty Argument¶
PHP allows the last element of any functioncall to be empty. The argument is then not send.
This was introduced in PHP 7.3, and is not backward compatible.
The last empty line is easier on the VCS, allowing clearer text diffs.
<?php
function foo($a, $b) {
print_r(func_get_args());
}
foo(1,
2,
);
foo(1);
?>
See also Allow a trailing comma in function calls and Trailing commas.
1.2.830.1. Specs¶
Short name |
Php/PHP73LastEmptyArgument |
Rulesets |
CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, CompatibilityPHP70, CompatibilityPHP71, CompatibilityPHP72, All |
Exakat since |
1.1.7 |
PHP Version |
7.3+ |
Severity |
Critical |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.831. PHP 8.0 Typehints¶
New scalar typehints were introduced : mixed and false.
They can’t be used before PHP 8.0, and will be confused with classes or interfaces, or generate a parse error.
<?php
function test(mixed $a) : false|other
{
//....
}
?>
See also PHP RFC: noreturn type
1.2.831.1. Specs¶
Short name |
Php/PHP80scalartypehints |
Rulesets |
CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, CompatibilityPHP70, CompatibilityPHP71, CompatibilityPHP72, CompatibilityPHP73, CompatibilityPHP74, All |
Exakat since |
2.3.0 |
PHP Version |
8.0+ |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
Very high |
Available in |
1.2.832. PHP 8.1 Typehints¶
A new scalar typehint was introduced : never.
It can’t be used before PHP 8.1, and will be confused with classes or interfaces.
<?php
function test() : never
{
exit();
}
?>
See also PHP RFC: noreturn type
1.2.832.1. Specs¶
Short name |
Php/PHP81scalartypehints |
Rulesets |
CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, CompatibilityPHP70, CompatibilityPHP71, CompatibilityPHP72, CompatibilityPHP73, CompatibilityPHP74, CompatibilityPHP80, All |
Exakat since |
2.3.0 |
PHP Version |
8.1+ |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
Very high |
Available in |
1.2.833. Parenthesis As Parameter¶
Using parenthesis around parameters used to silent some internal check. This is not the case anymore in PHP 7, and should be fixed by removing the parenthesis and making the value a real reference.
<?php
// example extracted from the PHP manual
function getArray() {
return [1, 2, 3];
}
function squareArray(array &$a) {
foreach ($a as &$v) {
$v \*\*\= 2;
}
}
// Generates a warning in PHP 7.
squareArray((getArray()));
?>
See also Parentheses around function arguments no longer affect behaviour.
1.2.833.1. Suggestions¶
Remove the parenthesis when they are only encapsulating an argument
Replace the parenthesis by the no-scream operator
1.2.833.2. Specs¶
Short name |
Php/ParenthesisAsParameter |
Rulesets |
CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, All |
Exakat since |
0.8.4 |
PHP Version |
7.0- |
PHP deprecated |
With PHP 7.0 and more recent |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.834. Use password_hash()¶
password_hash() and password_check() are a better choice to replace the use of crypt() to check password.
PHP 5.5 introduced these functions.
<?php
$password = 'rasmuslerdorf';
$hash = '\$2y\$10$YCFsG6elYca568hBi2pZ0.3LDL5wjgxct1N8w/oLR/jfHsiQwCqTS';
// The cost parameter can change over time as hardware improves
$options = array('cost' => 11);
// Verify stored hash against plain-text password
if (password_verify($password, $hash)) {
// Check if a newer hashing algorithm is available
// or the cost has changed
if (password_needs_rehash($hash, PASSWORD_DEFAULT, $options)) {
// If so, create a new hash, and replace the old one
$newHash = password_hash($password, PASSWORD_DEFAULT, $options);
}
// Log user in
}
?>
See also Password hashing.
1.2.834.1. Specs¶
Short name |
Php/Password55 |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
5.5+ |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.835. Pathinfo() Returns May Vary¶
pathinfo() function returns an array whose content may vary. It is recommended to collect the values after check, rather than directly.
<?php
$file = '/a/b/.c';
//$extension may be missing, leading to empty $filename and filename in $extension
list( $dirname, $basename, $extension, $filename ) = array_values( pathinfo($file) );
//Use PHP 7.1 list() syntax to assign correctly the values, and skip array_values()
//This emits a warning in case of missing index
['dirname' => $dirname,
'basename' => $basename,
'extension' => $extension,
'filename' => $filename ] = pathinfo($file);
//This works without warning
$details = pathinfo($file);
$dirname = $details['dirname'] ?? getpwd();
$basename = $details['basename'] ?? '';
$extension = $details['extension'] ?? '';
$filename = $details['filename'] ?? '';
?>
The same applies to parse_url(), which returns an array with various index.
1.2.835.1. Suggestions¶
Add a check on the return value of pathinfo() before using it.
1.2.835.2. Specs¶
Short name |
Php/PathinfoReturns |
Rulesets |
|
Exakat since |
0.12.11 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.836. Pear Usage¶
Pear Usage : list of Pear packages in use.
<?php
require_once('MDB2.php');
$dsn = 'mysql://user:pass@host';
$mdb2 = &MDB2::factory($dsn);
$mdb2->setFetchMode(MDB2_FETCHMODE_ASSOC);
?>
See also PEAR.
1.2.836.1. Specs¶
Short name |
Php/PearUsage |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.837. New Functions In PHP 5.4¶
PHP introduced new functions in PHP 5.4. If there are defined functions with such names, there will be a conflict when upgrading. It is advised to change those functions’ name.
1.2.837.1. Specs¶
Short name |
Php/Php54NewFunctions |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.838. Functions Removed In PHP 5.4¶
Those functions were removed in PHP 5.4.
<?php
// Deprecated as of PHP 5.4.0
$link = mysql_connect('localhost', 'mysql_user', 'mysql_password');
$db_list = mysql_list_dbs($link);
while ($row = mysql_fetch_object($db_list)) {
echo $row->Database . "\n";
}
?>
See also Deprecated features in PHP 5.4.x.
1.2.838.1. Specs¶
Short name |
Php/Php54RemovedFunctions |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.839. New Functions In PHP 5.5¶
PHP introduced new functions in PHP 5.5. If you have already defined functions with such names, you will get a conflict when trying to upgrade. It is advised to change those functions’ name.
1.2.839.1. Specs¶
Short name |
Php/Php55NewFunctions |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.840. Functions Removed In PHP 5.5¶
Those functions were removed in PHP 5.5.
<?php
echo '<img src="' . $_SERVER['PHP_SELF'] .
'?=' . php_logo_guid() . '" alt="PHP Logo !" />';
?>
See also Deprecated features in PHP 5.5.x.
1.2.840.1. Suggestions¶
Stop using those functions
1.2.840.2. Specs¶
Short name |
Php/Php55RemovedFunctions |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.841. New Functions In PHP 5.6¶
PHP introduced new functions in PHP 5.6. If you have already defined functions with such names, you will get a conflict when trying to upgrade. It is advised to change those functions’ name.
1.2.841.1. Specs¶
Short name |
Php/Php56NewFunctions |
Rulesets |
CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, All |
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.842. PHP 7.0 New Classes¶
Those classes are now declared natively in PHP 7.0 and should not be declared in custom code.
There are 8 new classes :
ErrorParseErrorTypeErrorArithmeticErrorDivisionByZeroErrorClosedGeneratorExceptionReflectionGeneratorReflectionTypeAssertionError
<?php
namespace {
// Global namespace
class Error {
// Move to a namespace
// or, remove this class
}
}
namespace B {
class Error {
// This is OK : in a namespace
}
}
?>
See also New Classes and Interfaces.
1.2.842.1. Specs¶
Short name |
Php/Php70NewClasses |
Rulesets |
CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, All |
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.843. New Functions In PHP 7.0¶
The following functions are now native functions in PHP 7.0. It is advised to change them before moving to this new version.
get_resources()
posix_setrlimit()
1.2.843.1. Specs¶
Short name |
Php/Php70NewFunctions |
Rulesets |
CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, All |
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.844. PHP 7.0 New Interfaces¶
The following interfaces are introduced in PHP 7.0. They shouldn’t be defined in custom code.
1.2.844.1. Specs¶
Short name |
Php/Php70NewInterfaces |
Rulesets |
CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, All |
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.845. PHP 7.0 Removed Directives¶
List of directives that are removed in PHP 7.0.
1.2.845.1. Specs¶
Short name |
Php/Php70RemovedDirective |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.846. PHP 7.0 Removed Functions¶
The following PHP native functions were removed in PHP 7.0.
datefmt_set_timezone_id()
This analysis skips redefined PHP functions : when a replacement for a removed PHP function was created, with condition on the PHP version, then its usage is considered valid.
See also PHP 7.0 Removed Functions.
1.2.846.1. Suggestions¶
Replace the old functions with modern functions
Remove the usage of the old functions
Create an alternative function by wiring the old name to a new feature
1.2.846.2. Specs¶
Short name |
Php/Php70RemovedFunctions |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.847. Php 7.1 New Class¶
New classes, introduced in PHP 7.1. If classes where created with the same name, in current code, they have to be moved in a namespace, or removed from code to migrate safely to PHP 7.1.
The new class is : ReflectionClassConstant. The other class is ‘Void’ : this is forbidden as a class name, as Void is used for return type hint.
<?php
class ReflectionClassConstant {
// Move to a namespace, do not leave in global
// or, remove this class
}
?>
1.2.847.1. Specs¶
Short name |
Php/Php71NewClasses |
Rulesets |
CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, CompatibilityPHP70, All |
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.848. New Functions In PHP 7.1¶
The following functions are now native functions in PHP 7.1. It is advised to change them before moving to this new version.
1.2.848.1. Specs¶
Short name |
Php/Php71NewFunctions |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
Very high |
Available in |
1.2.849. PHP 7.1 Removed Directives¶
List of directives that are removed in PHP 7.1.
1.2.849.1. Specs¶
Short name |
Php/Php71RemovedDirective |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
7.1+ |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.850. PHP 7.1 Microseconds¶
PHP supports microseconds in
DateTimeclass and date_create() function. This was introduced in PHP 7.1.
In previous PHP versions, those dates only used seconds, leading to lazy comparisons :
<?php
$now = date_create();
usleep(10); // wait for 0.001 ms
var_dump($now == date_create());
?>
This code displays true in PHP 7.0 and older, (unless the code was run too close from the next second). In PHP 7.1, this is always false.
This is also true with DateTime :
<?php
$now = new DateTime();
usleep(10); // wait for 0.001 ms
var_dump((new DateTime())->format('u') == $now->format('u'));
?>
This evolution impacts mostly exact comparisons (== and ===). Non-equality (!= and !==) will probably be always true, and should be reviewed.
See also Backward incompatible changes.
1.2.850.1. Specs¶
Short name |
Php/Php71microseconds |
Rulesets |
|
Exakat since |
0.8.9 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.851. PHP 7.2 Deprecations¶
Several functions are deprecated in PHP 7.2.
parse_str() with no second argument
assert() on strings
Usage of gmp_random(), create_function(), each()
Usage of (unset)
Usage of
$php_errormsgdirective
mbstring.func_overload(not supported yet)
Deprecated functions and extensions are reported in a separate analysis.
See also Deprecations for PHP 7.2.
1.2.851.1. Suggestions¶
Remove the deprecated functions, and replace them with a new feature
Use a replacement function to emulate this old behavior
1.2.851.2. Specs¶
Short name |
Php/Php72Deprecation |
Rulesets |
|
Exakat since |
0.9.9 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.852. Php 7.2 New Class¶
New classes, introduced in PHP 7.2. If classes where created with the same name, in current code, they have to be moved in a namespace, or removed from code to migrate safely to PHP 7.2.
The new class is : HashContext.
<?php
namespace {
// Global namespace
class HashContext {
// Move to a namespace
// or, remove this class
}
}
namespace B {
class HashContext {
// This is OK : in a namespace
}
}
?>
1.2.852.1. Specs¶
Short name |
Php/Php72NewClasses |
Rulesets |
CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, CompatibilityPHP70, CompatibilityPHP71, CompatibilityPHP72, All |
Exakat since |
1.0.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.853. New Constants In PHP 7.2¶
The following constants are now native in PHP 7.2. It is advised to avoid using such names for constant before moving to this new version.
PHP_OS_FAMILYPHP_FLOAT_DIGPHP_FLOAT_EPSILONPHP_FLOAT_MAXPHP_FLOAT_MINSQLITE3_DETERMINISTICCURLSSLOPT_NO_REVOKECURLOPT_DEFAULT_PROTOCOLCURLOPT_STREAM_WEIGHTCURLMOPT_PUSHFUNCTIONCURL_PUSH_OKCURL_PUSH_DENYCURL_HTTP_VERSION_2TLSCURLOPT_TFTP_NO_OPTIONSCURL_HTTP_VERSION_2_PRIOR_KNOWLEDGECURLOPT_CONNECT_TOCURLOPT_TCP_FASTOPENDNS_CAA
1.2.853.1. Suggestions¶
Move the constants to a new namespace
Remove the old constants
Rename the old constants
See also and New global constants in 7.2.
1.2.853.2. Specs¶
Short name |
Php/Php72NewConstants |
Rulesets |
|
Exakat since |
0.10.7 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
Very high |
Available in |
1.2.854. New Functions In PHP 7.2¶
The following functions are now native functions in PHP 7.2. It is advised to change custom functions that are currently created, and using those names, before moving to this new version.
proc_nice() (Windows only)
1.2.854.1. Suggestions¶
Move custom functions with the same name to a new namespace
Change the name of any custom functions with the same name
Add a condition to the functions definition to avoid conflict
1.2.854.2. Specs¶
Short name |
Php/Php72NewFunctions |
Rulesets |
|
Exakat since |
0.10.7 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
Very high |
Available in |
1.2.855. PHP 7.2 Object Keyword¶
‘object’ is a PHP keyword. It can’t be used for class, interface or trait name.
This is the case since PHP 7.2.
<?php
// Valid until PHP 7.2
class object {}
// Altough it is really weird anyway...
?>
See also List of Keywords.
1.2.855.1. Specs¶
Short name |
Php/Php72ObjectKeyword |
Rulesets |
|
Exakat since |
0.12.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.856. PHP 7.2 Removed Functions¶
The following PHP native functions were removed in PHP 7.2.
This analysis skips redefined PHP functions : when a replacement for a removed PHP function was created, with condition on the PHP version, then its usage is considered valid.
See also Deprecated features in PHP 7.2.x.
1.2.856.1. Specs¶
Short name |
Php/Php72RemovedFunctions |
Rulesets |
|
Exakat since |
0.9.9 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.857. New Functions In PHP 7.3¶
New functions are added to new PHP version.
The following functions are now native functions in PHP 7.3. It is compulsory to rename any custom function that was created in older versions. One alternative is to move the function to a custom namespace, and update the use list at the beginning of the script.
net_get_interfaces()
gmp_binomial()
gmp_lcm()
gmp_perfect_power()
gmp_kronecker()
openssl_pkey_derive()
is_countable()
ldap_exop_refresh()
Note : At the moment of writing, all links to the manual are not working.
1.2.857.1. Specs¶
Short name |
Php/Php73NewFunctions |
Rulesets |
CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, CompatibilityPHP70, CompatibilityPHP71, CompatibilityPHP72, CompatibilityPHP73, All |
Exakat since |
0.10.7 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.858. PHP 7.3 Removed Functions¶
The following PHP native functions were removed in PHP 7.3.
This analysis skips redefined PHP functions : when a replacement for a removed PHP function was created, with condition on the PHP version, then its usage is considered valid.
See also PHP 7.3 Removed Functions.
1.2.858.1. Specs¶
Short name |
Php/Php73RemovedFunctions |
Rulesets |
|
Exakat since |
1.4.0 |
PHP Version |
All |
Severity |
Critical |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.859. PHP 7.4 Constant Deprecation¶
One constant is deprecated in PHP 7.4.
See also Deprecations for PHP 7.2.
1.2.859.1. Suggestions¶
Use CURLPIPE_MULTIPLEX or CURLPIPE_NOTHING
1.2.859.2. Specs¶
Short name |
Php/Php74Deprecation |
Rulesets |
|
Exakat since |
1.9.3 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.860. Php 7.4 New Class¶
New classes, introduced in PHP 7.4. If classes where created with the same name, in current code, they have to be moved in a namespace, or removed from code to migrate safely to PHP 7.4.
The new classes are :
ReflectionReferenceWeakReference
<?php
namespace {
// Global namespace
class WeakReference {
// Move to a namespace
// or, remove this class
}
}
namespace B {
class WeakReference {
// This is OK : in a namespace
}
}
?>
1.2.860.1. Suggestions¶
Move the current classes with the same names into a distinct domain name
1.2.860.2. Specs¶
Short name |
Php/Php74NewClasses |
Rulesets |
|
Exakat since |
1.0.4 |
PHP Version |
7.4- |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.861. New Constants In PHP 7.4¶
The following constants are now native in PHP 7.4. It is advised to avoid using such names for constant before moving to this new version.
MB_ONIGURUMA_VERSIONSO_LABELSO_PEERLABELSO_LISTENQLIMITSO_LISTENQLENSO_USER_COOKIEPHP_WINDOWS_EVENT_CTRL_CPHP_WINDOWS_EVENT_CTRL_BREAKTIDY_TAG_ARTICLETIDY_TAG_ASIDETIDY_TAG_AUDIOTIDY_TAG_BDITIDY_TAG_CANVASTIDY_TAG_COMMANDTIDY_TAG_DATALISTTIDY_TAG_DETAILSTIDY_TAG_DIALOGTIDY_TAG_FIGCAPTIONTIDY_TAG_FIGURETIDY_TAG_FOOTERTIDY_TAG_HEADERTIDY_TAG_HGROUPTIDY_TAG_MAINTIDY_TAG_MARKTIDY_TAG_MENUITEMTIDY_TAG_METERTIDY_TAG_NAVTIDY_TAG_OUTPUTTIDY_TAG_PROGRESSTIDY_TAG_SECTIONTIDY_TAG_SOURCETIDY_TAG_SUMMARYTIDY_TAG_TEMPLATETIDY_TAG_TIMETIDY_TAG_TRACKTIDY_TAG_VIDEOSTREAM_CRYPTO_METHOD_TLSv1_3_CLIENTSTREAM_CRYPTO_METHOD_TLSv1_3_SERVERSTREAM_CRYPTO_PROTO_TLSv1_3T_COALESCE_EQUALT_FN
1.2.861.1. Suggestions¶
Move the constants to a new namespace
Remove the old constants
Rename the old constants
See also and New global constants in 7.4.
1.2.861.2. Specs¶
Short name |
Php/Php74NewConstants |
Rulesets |
|
Exakat since |
1.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
Very high |
Available in |
1.2.862. PHP 74 New Directives¶
List of directives that are new in PHP 7.4.
zend.exception_ignore_args: From the php.ini :Allows to include or exclude arguments from stack traces generated for exceptions. Default: Offopcache.preload_user
See RFC Preload.
1.2.862.1. Suggestions¶
Do not use those directives with PHP before version 7.4
1.2.862.2. Specs¶
Short name |
Php/Php74NewDirective |
Rulesets |
|
Exakat since |
1.9.4 |
PHP Version |
7.4- |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.863. New Functions In PHP 7.4¶
New functions are added to new PHP version.
The following functions are now native functions in PHP 7.3. It is compulsory to rename any custom function that was created in older versions. One alternative is to move the function to a custom namespace, and update the use list at the beginning of the script.
mb_str_split()
password_algos()
1.2.863.1. Specs¶
Short name |
Php/Php74NewFunctions |
Rulesets |
|
Exakat since |
1.8.0 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.864. PHP 7.4 Removed Directives¶
List of directives that are removed in PHP 7.4.
allow_url_include
See Deprecation allow_url_include.
1.2.864.1. Suggestions¶
Stop using this directive
1.2.864.2. Specs¶
Short name |
Php/Php74RemovedDirective |
Rulesets |
CE, CompatibilityPHP74, CompatibilityPHP80, CompatibilityPHP81, All |
Exakat since |
1.9.3 |
PHP Version |
7.4+ |
PHP deprecated |
7.4 |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.865. PHP 7.4 Removed Functions¶
The following PHP native functions were deprecated in PHP 7.4.
This analysis skips redefined PHP functions : when a replacement for a removed PHP function was created, with condition on the PHP version, then its usage is considered valid.
See also PHP 7.4 Removed Functions and PHP 7.4 Deprecations : Introduction.
1.2.865.1. Specs¶
Short name |
Php/Php74RemovedFunctions |
Rulesets |
|
Exakat since |
1.9.0 |
PHP Version |
All |
Severity |
Critical |
Time To Fix |
Slow (1 hour) |
Precision |
Very high |
Available in |
1.2.866. PHP 7.4 Reserved Keyword¶
fnis a new PHP keyword. In PHP 7.4, it is used to build the arrow functions. When used at an illegal position,fngenerates a Fatal error at compile time.
As a key word, fn is not allowed as constant name, function name, class name or inside namespaces.
<?php
// PHP 7.4 usage of fn
function array_values_from_keys($arr, $keys) {
return array_map(fn($x) => $arr[$x], $keys);
}
// PHP 7.3 usage of fn
const fn = 1;
function fn() {}
class x {
// This is valid in PHP 7.3 and 7.4
function fn() {}
}
?>
fn is fine for method names. It may also be used for constants with define(), and constant() but it is not recommended.
See also PHP RFC: Arrow Functions.
1.2.866.1. Specs¶
Short name |
Php/Php74ReservedKeyword |
Rulesets |
|
Exakat since |
1.9.2 |
PHP Version |
7.4- |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.867. mb_strrpos() Third Argument¶
Passing the encoding as 3rd parameter to mb_strrpos() is deprecated. Instead pass a 0 offset, and encoding as 4th parameter.
<?php
// Finds the position of the last occurrence of of a string in a string, starting at position 10
$extract = mb_strrpos($haystack, $needle, 10, 'utf8');
// This is the old behavior. Here, the offset will be 0, by default
$extract = mb_strrpos($haystack, $needle, 'utf8');
?>
See also mb_strrpos().
1.2.867.1. Specs¶
Short name |
Php/Php74mbstrrpos3rdArg |
Rulesets |
|
Exakat since |
1.8.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.868. Php7 Relaxed Keyword¶
Most of the traditional PHP keywords may be used inside classes, trait or interfaces.
<?php
// Compatible with PHP 7.0 +
class foo {
// as is a PHP 5 keyword
public function as() {
}
}
?>
This was not the case in PHP 5, and will yield parse errors.
See also Loosening Reserved Word Restrictions.
1.2.868.1. Specs¶
Short name |
Php/Php7RelaxedKeyword |
Rulesets |
Appinfo, CE, CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, All |
Exakat since |
0.8.4 |
PHP Version |
7.0+ |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.869. PHP 80 Named Parameter Variadic¶
Named parameter with variadic have been renamed from 0 to ‘parameter name’ in PHP 8.0
<?php
function foo($a, ...$b) {
print_r($b);
}
foo(3, 4);
foo(3, b: 4); // PHP 8 only
foo(...[2, b=> [3, 4]]); // PHP 8 only
?>
In PHP 7.0, with positional argument only, the content of $b is in an array, index 0. This is also true with PHP 8.0.
In PHP 8.0, with named arguments, the content of $b is in an array, index ‘b’;
Since the behavior of the variadic depends on the calling syntax (with or without named parameter), the receiving must ensure the correct reception, and handle both cases.
1.2.869.1. Suggestions¶
Apply array_values() to the variadic arguments.
1.2.869.2. Specs¶
Short name |
Php/Php80NamedParameterVariadic |
Rulesets |
|
Exakat since |
2.2.0 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Medium |
Available in |
1.2.870. New Functions In PHP 8.0¶
New functions are added to new PHP version.
The following functions are now native functions in PHP 8.0. It is compulsory to rename any custom function that was created in older versions. One alternative is to move the function to a custom namespace, and update the use list at the beginning of the script.
str_contains()
fdiv()
1.2.870.1. Specs¶
Short name |
Php/Php80NewFunctions |
Rulesets |
|
Exakat since |
2.0.8 |
PHP Version |
8.0- |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.871. Php 8.0 Only TypeHints¶
Two scalar typehints are introduced in version 8. They are
falseandnull. In PHP 7.0, both those values could not be used as a class or interface name, to avoid confusion with the actual booleans, nornullvalue.
false represents a false boolean, and nothing else. It is more restrictive than a boolean, which accepts true too.
null is an alternative syntax to ? : it allows the type to be null.
Both the above typehints are to be used in cunjunction with other types : they can’t be used alone.
<?php
// function accepts an A object, or null.
function foo(A|null $x) {}
// same as above
function foo2(A|null $x) {}
// returns an object of class B, or false
function bar($x) : false|B {}
?>
See also PHP RFC: Union Types 2.0.
1.2.871.1. Specs¶
Short name |
Php/Php80OnlyTypeHints |
Rulesets |
Appinfo, CE, CompatibilityPHP56, CompatibilityPHP70, CompatibilityPHP71, CompatibilityPHP72, CompatibilityPHP73, CompatibilityPHP74, All |
Exakat since |
2.0.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Available in |
1.2.872. PHP 8.0 Removed Constants¶
The following PHP native constants were removed in PHP 8.0.
INTL_IDNA_VARIANT_2003 (See Deprecate and remove `INTL_IDNA_VARIANT_2003 <https://wiki.php.net/rfc/deprecate-and-remove-intl_idna_variant_2003>`_)
1.2.872.1. Suggestions¶
Remove usage of those constants
1.2.872.2. Specs¶
Short name |
Php/Php80RemovedConstant |
Rulesets |
|
Exakat since |
1.6.8 |
PHP Version |
8.0- |
Severity |
Critical |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.873. PHP 8.0 Removed Directives¶
List of directives that are removed in PHP 8.0.
In PHP 8.0, track_errors was removed.
You can detect valid directives with ini_get(). This native function will return false, when the directive doesn’t exist, while actual directive values will be returned as a string.
See Deprecation `track_errors <https://www.php.net/manual/en/migration80.incompatible.php`_.
1.2.873.1. Suggestions¶
Remove usage of track_errors.
1.2.873.2. Specs¶
Short name |
Php/Php80RemovedDirective |
Rulesets |
|
Exakat since |
2.1.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.874. PHP 8.0 Removed Functions¶
The following PHP native functions were deprecated in PHP 8.0, and will be removed in PHP 9.0
1.2.874.1. Suggestions¶
Remove usage of any of those functions.
1.2.874.2. Specs¶
Short name |
Php/Php80RemovedFunctions |
Rulesets |
|
Exakat since |
1.6.8 |
PHP Version |
8.0- |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.875. PHP 8.0 Resources Turned Into Objects¶
Multiple PHP native functions now return objects, not resources. Any check on those values with is_resource() is now going to fail.
The affected functions are the following :
deflate_init()
inflate_init()
See also Resource to object migration.
1.2.875.1. Suggestions¶
Change the condition from is_resource() to instanceof
1.2.875.2. Specs¶
Short name |
Php/Php80RemovesResources |
Rulesets |
|
Exakat since |
2.2.0 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
Medium |
Available in |
1.2.876. Union Typehint¶
Union typehints allows the specification of several typehint for the same argument or return value.
Several typehints are specified at the same place as a single one. The different values are separated by a pipe character |, like for exceptions
<?php
// Example from the RFC https://wiki.php.net/rfc/union_types_v2
class Number {
private int|float $number;
public function setNumber(int|float $number): void {
$this->number = $number;
}
public function getNumber(): int|float {
return $this->number;
}
}
?>
Nullable is reported as union type. Mixed and iterable are not reported as a union type.
Union types are a PHP 8.0 new feature. They are not compatible with PHP 7.4 and older. See also PHP RFC: Union Types 2.0, PHP 8 Union types and Type declarations.
1.2.876.1. Specs¶
Short name |
Php/Php80UnionTypehint |
Rulesets |
Appinfo, CE, CompatibilityPHP70, CompatibilityPHP71, CompatibilityPHP72, CompatibilityPHP73, CompatibilityPHP74, All |
Exakat since |
2.0.9 |
PHP Version |
With PHP 8.0 and more recent |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Available in |
1.2.877. Php 8.0 Variable Syntax Tweaks¶
Several variable syntaxes are added in version 8.0. They extends the PHP 7.0 syntax updates, and fix a number of edges cases.
In particular, new``and ``instanceof now support a way to inline the expression, rather than use a temporary variable.
Magic constants are now accessible with array notation, just like another constant. It is also possible to use method calls : although this is Syntacticly correct for PHP, this won’t be executed, as the left operand is a string, and not an object.
<?php
// array name is dynamically build
echo foo$bar[0];
// static method
foo$bar::baz();
// static property
foo$bar::$baz;
// Syntactly correct, but not executable
foo$bar->baz();
// expressions with instanceof and new
$object = new (class_.$name);
$x instanceof (class_$name);
// PHP 7.0 style
$className = class_.$name;
$object = new $className;
?>
See also PHP RFC: Variable Syntax Tweaks and scalar_objects in PHP.
1.2.877.1. Specs¶
Short name |
Php/Php80VariableSyntax |
Rulesets |
|
Exakat since |
2.0.8 |
PHP Version |
8.0+ |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.878. PHP 8.1 Removed Constants¶
The following PHP native constants were disabled in PHP 8.1. They are not removed, but they have no more effect.
See PHP RFC: Deprecations for PHP 8.1.
1.2.878.1. Suggestions¶
Remove usage of those constants
1.2.878.2. Specs¶
Short name |
Php/Php81RemovedConstant |
Rulesets |
|
Exakat since |
1.6.8 |
PHP Version |
8.1- |
Severity |
Critical |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.879. PHP 8.1 Removed Directives¶
List of directives that are removed in PHP 8.1.
In PHP 8.1, the following directives were removed :
mysqlnd.fetch_data_copy
filter.default
filter.default_options
auto_detect_line_endings
oci8.old_oci_close_semantics
You can detect valid directives with ini_get(). This native function will return false, when the directive doesn’t exist, while actual directive values will be returned as a string.
See PHP RFC: Deprecations for PHP 8.1.
1.2.879.1. Suggestions¶
Remove usage of the directives.
1.2.879.2. Specs¶
Short name |
Php/Php81RemovedDirective |
Rulesets |
|
Exakat since |
2.2.3 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.880. $php_errormsg Usage¶
$php_errormsg is removed since PHP 8.0. $php_errormsg tracks the last error message, with the directive track_errors. All was removed in PHP 8.0, and shall be replaced with error_get_last().
<?php
function foo() {
global $php_errormsg;
echo 'Last error: '.$php_errormsg;
echo 'Also, last error: '.error_get_last();
}
?>
1.2.880.1. Suggestions¶
Use error_get_last() instead.
1.2.880.2. Specs¶
Short name |
Php/PhpErrorMsgUsage |
Rulesets |
|
Exakat since |
2.1.8 |
PHP Version |
8.0- |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.881. preg_match_all() Flag¶
preg_match_all() has an option to configure the structure of the results : it is either by capturing parenthesis (by default), or by result sets.
The second option is the most interesting when the following foreach() loop has to manipulate several captured strings at the same time. No need to use an index in the first array and use it in the other arrays.
<?php
$string = 'ababab';
// default behavior
preg_match_all('/(a)(b)/', $string, $r);
$found = '';
foreach($r[1] as $id => $s) {
$found .= $s.$r[2][$id];
}
// better behavior
preg_match_all('/(a)(b)/', $string, $r, PREG_SET_ORDER);
$found = '';
foreach($r as $s) {
$found .= $s[1].$s[2];
}
?>
The second syntax is easier to read and may be marginally faster to execute (preg_match_all() and foreach()).
1.2.881.1. Suggestions¶
Use flags to adapt the results of preg_match_all() to your code, not the contrary.
1.2.881.2. Specs¶
Short name |
Php/PregMatchAllFlag |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.882. Displays Text¶
Function calls that displays something to the output.
<?php
// Displays de the content of $a
print $a;
// Displays de the content of $b
print_r($b);
// Returns de the content of $b, no display.
$c = var_export($b, true);
?>
1.2.882.1. Specs¶
Short name |
Php/Prints |
Rulesets |
|
Exakat since |
0.10.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.883. $HTTP_RAW_POST_DATA Usage¶
$HTTP_RAW_POST_DATAis deprecated, and should be replaced byphp://input.
$HTTP_RAW_POST_DATA is deprecated since PHP 5.6.
It is possible to prepare code to this lack of feature by setting always_populate_raw_post_data to -1.
<?php
// PHP 5.5 and older
$postdata = $HTTP_RAW_POST_DATA;
// PHP 5.6 and more recent
$postdata = file_get_contents(php://input);
?>
See also $HTTP_RAW_POST_DATA variable.
1.2.883.1. Suggestions¶
Use php://input with fopen() instead.
1.2.883.2. Specs¶
Short name |
Php/RawPostDataUsage |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.884. Reflection Export() Is Deprecated¶
export() method in Reflection classes is now deprecated. It is obsolete since PHP 7.4 and will disappear in PHP 8.0.
The Reflector interface, which is implemented by all reflection classes, specifies two methods: __toString() and export().
<?php
ReflectionFunction::export('foo');
// same as
echo new ReflectionFunction('foo'), \n;
$str = ReflectionFunction::export('foo', true);
// same as
$str = (string) new ReflectionFunction('foo');
?>
See also Reflection export() methods and Reflection.
1.2.884.1. Suggestions¶
Cast the object to string
Remove the call to export()
1.2.884.2. Specs¶
Short name |
Php/ReflectionExportIsDeprecated |
Rulesets |
|
Exakat since |
1.9.0 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.885. Reserved Keywords In PHP 7¶
PHP reserved names for class/trait/interface. They won’t be available anymore in user space starting with PHP 7.
For example, string, float, false, true, null, resource,`… <https://www.php.net/manual/en/functions.arguments.php#functions.variable-arg-list>`_ are not acceptable as class name.
<?php
// This doesn't compile in PHP 7.0 and more recent
class null { }
?>
See also List of other reserved words.
1.2.885.1. Suggestions¶
Avoid using PHP reserved keywords
1.2.885.2. Specs¶
Short name |
Php/ReservedKeywords7 |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
7.0- |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.886. Reserved Match Keyword¶
Match is a new instruction in PHP 8.0. For that, it becomes a reserved keyword, and cannot be used in various situations.
<?php
// Match as a standalone keyword
use X as Match;
// No more use as a typehint
function foo(match $a ) : match {}
$a instanceof match;
// No use as method name or function name
matCH(a, 4) ;
$method->MAtch();
$static::MATch();
// Match in a Fully qualified name is OK
b\match ;
// Match a property name or a class constant is OK
$match->maTCH;
C::MATCH;
?>
See also Match expression V2.
1.2.886.1. Suggestions¶
Change the name from Match to something else.
1.2.886.2. Specs¶
Short name |
Php/ReservedMatchKeyword |
Rulesets |
|
Exakat since |
2.2.1 |
PHP Version |
8.0- |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Unknown |
Available in |
1.2.887. PHP Keywords As Names¶
PHP has a set of reserved keywords. It is recommended not to use those keywords for names structures.
PHP does check that a number of structures, such as classes, methods, interfaces… can’t be named or called using one of the keywords. However, in a few other situations, no check are enforced. Using keywords in such situation is confusing.
<?php
// This keyword is reserved since PHP 7.2
class object {
// _POST is used by PHP for the $_POST variable
// This methods name is probably confusing,
// and may attract more than its share of attention
function _POST() {
}
}
?>
See also List of Keywords, Predefined Classes, Predefined Constants, List of other reserved words and Predefined Variables.
1.2.887.1. Suggestions¶
Rename the structure
Choose another naming convention to avoid conflict and rename the current structures
Name |
Default |
Type |
Description |
reservedNames |
string |
Other reserved names : all in a string, comma separated. |
|
allowedNames |
string |
PHP reserved names that can be used in the code. All in a string, comma separated. |
1.2.887.2. Specs¶
Short name |
Php/ReservedNames |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.888. Restrict Global Usage¶
$GLOBALS access, as whole, is forbidden. In PHP 8.1, it is not possible to this as a variable, but only access its individual values.
<?php
// Example extracted from the RFC (see link below)
// Continues to work:
foreach ($GLOBALS as $var => $value) {
echo $var . ' => ' . $value . PHP_EOL;
}
// Generates compile-time error:
$GLOBALS = [];
$GLOBALS += [];
$GLOBALS =& $x;
$x =& $GLOBALS;
unset($GLOBALS);
?>
See also Restrict $GLOBALS usage.
1.2.888.1. Suggestions¶
Copy values individually from $GLOBALS
1.2.888.2. Specs¶
Short name |
Php/RestrictGlobalUsage |
Rulesets |
|
Exakat since |
2.2.2 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.889. Return Typehint Usage¶
Spot usage of return typehint. It is a PHP 7.0 feature.
Return typehint were introduced in PHP 7.0, and are backward incompatible with PHP 5.x.
<?php
function foo($a) : stdClass {
return new \stdClass();
}
?>
See also RFC: Return Type Declarations and Return Type Declarations.
1.2.889.1. Specs¶
Short name |
Php/ReturnTypehintUsage |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
7.0+ |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.890. Return With Parenthesis¶
return statement doesn’t need parenthesis. PHP tolerates them with return statement, but it is recommended not to use them.
From the PHP Manual : ‘Note: Note that since return is a language construct and not a function, the parentheses surrounding its argument are not required and their use is discouraged.’.
<?php
function foo() {
$a = rand(0, 10);
// No need for parenthesis
return $a;
// Parenthesis are useless here
return ($a);
// Parenthesis are useful here: they are needed by the multplication.
return ($a + 1) * 3;
}
?>
See also PHP return(value); vs return value; and return.
1.2.890.1. Suggestions¶
Remove the parenthesis
1.2.890.2. Specs¶
Short name |
Php/ReturnWithParenthesis |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.891. Safe Phpvariables¶
Mark the safe PHP variables.
PHP superglobales are usually filled with external data that should be filtered. However, some values may be considered safe, as they are under the control of the developer.
$_GET, $_POST, $_FILES, $_REQUEST, $_COOKIES are all considered unsafe. Their level of validation is checked in other analysis.
$_SERVER is partially safe. It is valid for the following values : DOCUMENT_ROOT, REQUEST_TIME, REQUEST_TIME_FLOAT, SCRIPT_NAME, SERVER_ADMIN, _.
<?php
// DOCUMENT_ROOT is a safe variable
echo $_SERVER['DOCUMENT_ROOT'];
// $_SERVER's PHP_SELF MUST be validated before usage
echo $_SERVER['PHP_SELF'];
// $_GET MUST be validated before usage
echo $_GET['_'];
?>
See also Predefined Variables.
1.2.891.1. Suggestions¶
1.2.891.2. Specs¶
Short name |
Php/SafePhpvars |
Rulesets |
|
Exakat since |
2.1.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.892. Scalar Are Not Arrays¶
It is wrong to use a scalar as an array, a Warning is emitted. PHP 7.4 emits a Warning in such situations.
<?php
// Here, $x may be null, and in that case, the echo will fail.
function foo(?A $x) {
echo $x[2];
}
?>
Typehinted argument with a scalar are reported by this analysis. Also, nullable arguments, both with typehint and return type hint.
See also E_WARNING for invalid container read array-access.
1.2.892.1. Suggestions¶
Update type hints to avoid scalar values
Remove the array syntax in the code using the results
Cast to string type, so the array notation is accessible
1.2.892.2. Specs¶
Short name |
Php/ScalarAreNotArrays |
Rulesets |
|
Exakat since |
1.9.0 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.893. Scalar Typehint Usage¶
Spot usage of scalar type hint :
int,float,booleanandstring.
Scalar typehint are PHP 7.0 and more recent. Some, like object, is 7.2.
Scalar typehint were not supported in PHP 5 and older. Then, the typehint is treated as a class name.
<?php
function withScalarTypehint(string $x) {}
function withoutScalarTypehint(someClass $x) {}
?>
See also PHP RFC: Scalar Type Hints and Type declarations.
1.2.893.1. Specs¶
Short name |
Php/ScalarTypehintUsage |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
7.0+ |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.894. Serialize Magic Method¶
Classes that defines __serialize() and __unserialize() are using Serialize Magic.
Serialize magic methods were introduced in PHP 7.4, and are not effective before.
<?php
class x {
function __serialize() {}
function __unserialize() {}
}
?>
See also New custom object serialization mechanism.
1.2.894.1. Specs¶
Short name |
Php/SerializeMagic |
Rulesets |
|
Exakat since |
1.9.0 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.895. Session Variables¶
Sessions names, used across the application.
<?php
if (isset($_SESSION['mySessionVariable'])) {
$_SESSION['mySessionVariable']['counter']++;
} else {
$_SESSION['mySessionVariable'] = array('counter' => 1,
'creation' => time());
}
?>
See also Sessions.
1.2.895.1. Specs¶
Short name |
Php/SessionVariables |
Rulesets |
|
Exakat since |
0.12.16 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.896. set_exception_handler() Warning¶
The set_exception_handler() callable function has to be adapted to PHP 7 :
Exceptionis not the right typehint, it is nowThrowable.
When in doubt about backward compatibility, just drop the typehint. Otherwise, use Throwable.
<?php
// PHP 5.6- typehint
class foo { function bar(\Exception $e) {} }
// PHP 7+ typehint
class foo { function bar(Throwable $e) {} }
// PHP 5 and PHP 7 compatible typehint (note : there is none)
class foo { function bar($e) {} }
set_exception_handler(foo);
?>
1.2.896.1. Specs¶
Short name |
Php/SetExceptionHandlerPHP7 |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.897. PHP Handlers Usage¶
PHP has a number of handlers that may be replaced by customized code : session, shutdown, error, exception. They are noted here.
The example is adapted from the PHP documentation of set_error_handler().
<?php
// error handler function
function myErrorHandler($errno, $errstr, $errfile, $errline)
{
if (!(error_reporting() & $errno)) {
// This error code is not included in error_reporting, so let it fall
// through to the standard PHP error handler
return false;
}
switch ($errno) {
case E_USER_ERROR:
echo '<b>My ERROR</b> [$errno] $errstr<br />'.PHP_EOL;
echo ' Fatal error on line '.$errline.' in file .'$errfile;
echo ', PHP ' . PHP_VERSION . ' (' . PHP_OS . ')<br />'.PHP_EOL;
echo 'Aborting...<br />'.PHP_EOL;
exit(1);
break;
case E_USER_WARNING:
echo '<b>My WARNING</b> ['.$errno.'] '.$errstr.'<br />'.PHP_EOL;
break;
case E_USER_NOTICE:
echo '<b>My NOTICE</b> ['.$errno.'] '.$errstr.'<br />'.PHP_EOL;
break;
default:
echo 'Unknown error type: ['.$errno.'] $errstr<br />'.PHP_EOL;
break;
}
/* Don't execute PHP internal error handler */
return true;
}
// set to the user defined error handler
$old_error_handler = set_error_handler(myErrorHandler);
?>
See also set_error_handler.
1.2.897.1. Specs¶
Short name |
Php/SetHandlers |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.898. Shell Favorite¶
PHP has several syntax to make system calls. shell_exec(), exec() and back-ticks, ` are the common ones.
It was found that one of those three is actually being used over 90% of the time. The remaining cases should be uniformed, so has to make this code consistent.
<?php
// back-ticks ` are only used once.
`back-tick`;
shell_exec('exec1');
shell_exec('exec2');
shell_exec('exec3');
shell_exec('exec4');
shell_exec('exec5');
shell_exec('exec6');
shell_exec('exec7');
shell_exec('exec8');
shell_exec('exec9');
shell_exec('exec10');
shell_exec('exec11');
shell_exec('exec12');
?>
See also Execution Operators and shell_exec().
1.2.898.1. Specs¶
Short name |
Php/ShellFavorite |
Rulesets |
|
Exakat since |
0.12.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.899. Short Open Tags¶
Usage of short open tags is discouraged. The following files were found to be impacted by the short open tag directive at compilation time. They must be reviewed to ensure no <? tags are found in the code.
1.2.899.1. Specs¶
Short name |
Php/ShortOpenTagRequired |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.900. Should Preprocess Chr()¶
Replace literal chr() calls with their escape sequence.
chr() is a functioncall, that cannot be cached. It is only resolved at execution time. On the other hand, literal values are preprocessed by PHP and may be cached.
<?php
// This is easier on PHP
$a = "\120\110\120\040 is great!";
// This is slow
$a = chr(80), chr(72), chr(80), chr(32), ' is great!';
// This would be the best with this example, but it is not always possible
$a = 'PHP is great!';
?>
This is a micro-optimisation.
See also Escape sequences.
1.2.900.1. Suggestions¶
Use PHP string sequences, and skip chr() at execution time
1.2.900.2. Specs¶
Short name |
Php/ShouldPreprocess |
Rulesets |
|
Exakat since |
1.1.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Examples |
|
Available in |
1.2.901. Should Use array_column()¶
Avoid writing a whole slow loop, and use the native array_column().
array_column() is a native PHP function, that extract a property or a index from a array of object, or a multidimensional array. This prevents the usage of foreach to collect those values.
<?php
$a = array(array('b' => 1),
array('b' => 2, 'c' => 3),
array( 'c' => 4)); // b doesn't always exists
$bColumn = array_column($a, 'b');
// Slow and cumbersome code
$bColumn = array();
foreach($a as $k => $v) {
if (isset($v['b'])) {
$bColumn[] = $v['b'];
}
}
?>
array_column() is faster than foreach() (with or without the isset() test) with 3 elements or more, and it is significantly faster beyond 5 elements. Memory consumption is the same.
See also [blog] `array_column() <https://benramsey.com/projects/array-column/>`_.
1.2.901.1. Suggestions¶
Use array_column(), instead of a foreach()
1.2.901.2. Specs¶
Short name |
Php/ShouldUseArrayColumn |
Rulesets |
|
Exakat since |
0.10.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.902. Should Use array_filter()¶
Should use array_filter().
array_filter() is a native PHP function, that extract elements from an array, based on a closure or a function. Using array_filter() shortens your code, and allows for reusing the filtering logic across the application, instead of hard coding it every time.
<?php
$a = range(0, 10); // integers from 0 to 10
// Extracts odd numbers
$odds = array_filter($a, function($x) { return $x % 2; });
$odds = array_filter($a, 'odd');
// Slow and cumbersome code for extracting odd numbers
$odds = array();
foreach($a as $v) {
if ($a % 2) { // same filter than the closure above, or the odd function below
$bColumn[] = $v;
}
}
function foo($x) {
return $x % 2;
}
?>
array_filter() is faster than foreach() (with or without the isset() test) with 3 elements or more, and it is significantly faster beyond 5 elements. Memory consumption is the same.
See also array_filter.
1.2.902.1. Suggestions¶
Use array_filter()
1.2.902.2. Specs¶
Short name |
Php/ShouldUseArrayFilter |
Rulesets |
|
Exakat since |
1.0.7 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Examples |
|
Available in |
1.2.903. Should Use Coalesce¶
PHP 7 introduced the
??operator, that replaces longer structures to set default values when a variable is not set.
<?php
// Fetches the request parameter user and results in 'nobody' if it doesn't exist
$username = $_GET['user'] ?? 'nobody';
// equivalent to: $username = isset($_GET['user']) ? $_GET['user'] : 'nobody';
// Calls a hypothetical model-getting function, and uses the provided default if it fails
$model = Model::get($id) ?? $default_model;
// equivalent to: if (($model = Model::get($id)) === NULL) { $model = $default_model; }
?>
Sample extracted from PHP docs Isset Ternary.
See also New in PHP 7: null coalesce operator.
1.2.903.1. Suggestions¶
Replace the long syntax with the short one
1.2.904. Should Use Function¶
Functioncalls that fall back to global scope should be using ‘use function’ or be fully namespaced.
PHP searches for functions in the local namespaces, and in case it fails, makes the same search in the global scope. Anytime a native function is referenced this way, the search (and fail) happens. This slows down the scripts.
The speed bump range from 2 to 8 %, depending on the availability of functions in the local scope. The overall bump is about 1 µs per functioncall, which makes it a micro optimisation until a lot of function calls are made.
Based on one of Marco Pivetta tweet.
<?php
namespace X {
use function strtolower as strtolower_aliased;
// PHP searches for strtolower in X, fails, then falls back to global scope, succeeds.
$a = strtolower($b);
// PHP searches for strtolower in global scope, succeeds.
$a = \strtolower($b);
// PHP searches for strtolower_aliased in global scope, succeeds.
$a = \strtolower_aliased($b);
}
?>
This analysis is a related to Performances/Php74ArrayKeyExists, and is a more general version.
See also blog post.
1.2.904.1. Suggestions¶
Use the use command for arrray_key_exists(), at the beginning of the script
Use an initial before array_key_exists()
Remove the namespace
1.2.904.2. Specs¶
Short name |
Php/ShouldUseFunction |
Rulesets |
|
Exakat since |
0.9.5 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.905. Signature Trailing Comma¶
Trailing comma in method signature. This feature was added in PHP 8.0.
Allowing the trailing comma makes it possible to reduce the size of VCS’s diff, when adding , removing a parameter.
<?php
// Example from the RFC
class Uri {
private function __construct(
?string $scheme,
?string $user,
?string $pass,
?string $host,
?int $port,
string $path,
?string $query,
?string $fragment // <-- ARGH!
) {
...
}
}
?>
See also PHP RFC: Allow trailing comma in parameter list.
1.2.905.1. Specs¶
Short name |
Php/SignatureTrailingComma |
Rulesets |
CE, CompatibilityPHP71, CompatibilityPHP72, CompatibilityPHP73, CompatibilityPHP74, All |
Exakat since |
2.1.0 |
PHP Version |
8.0+ |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.906. Spread Operator For Array¶
The variadic operator may be used with arrays. This has been introduced in PHP 7.4.
list() is not allowed to use this operator, as list() expected variables, not values.
<?php
$array = [1, 2, 3];
$extended_array = [...$array, 4, 5, 6];
// invalid syntax
[...$a] = [1,2,3];
?>
See also Spread Operator in Array Expression.
1.2.906.1. Specs¶
Short name |
Php/SpreadOperatorForArray |
Rulesets |
|
Exakat since |
1.9.4 |
PHP Version |
7.4+ |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.907. ::class¶
PHP has a special class constant to hold the name of the class :
classkeyword. It represents the class name that is used in the left part of the operator.
Using \:\:class is safer than relying on a string. It does adapt if the class’s name or its namespace is changed’. It is also faster, though it is a micro-optimisation.
It is introduced in PHP 5.5.
<?php
use A\B\C as UsedName;
class foo {
public function bar( ) {
echo ClassName::class;
echo UsedName::class;
}
}
$f = new Foo( );
$f->bar( );
// displays ClassName
// displays A\B\C
?>
Be aware that \:\:class is a replacement for __CLASS__ magic constant.
See also Class Constant.
1.2.907.1. Suggestions¶
Use ::class whenever possible. That exclude any dynamic call.
1.2.907.2. Specs¶
Short name |
Php/StaticclassUsage |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
5.5+ |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
Very high |
Available in |
1.2.908. Strtr Arguments¶
In particular, strtr() works on strings of the same size, and cannot be used to remove chars.
<?php
$string = 'abcde';
echo strtr($string, 'abc', 'AB');
echo strtr($string, 'ab', 'ABC');
// displays ABcde
// c is ignored each time
// strtr can't remove a char
echo strtr($string, 'a', '');
// displays a
?>
See also strtr.
1.2.908.1. Suggestions¶
Check the call to strtr() and make sure the arguments are of the same size
Replace strtr() with str_replace(), which works with strings and array, not chars
Replace strtr() with preg_match(), which works with patterns and not chars
1.2.908.2. Specs¶
Short name |
Php/StrtrArguments |
Rulesets |
|
Exakat since |
1.2.3 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.909. Super Global Usage¶
<?php
echo htmlspecialchars($_GET['name'], UTF-8);
?>
See also Superglobals.
1.2.909.1. Specs¶
Short name |
Php/SuperGlobalUsage |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.910. Throw¶
List of thrown exceptions.
<?php
if ($divisor === 0) {
// Throw native exception
throw new DivisionByZeroError("Shouldn't divide by one");
}
if ($divisor === 1) {
// Throw custom exception
throw new DontDivideByOneException("Shouldn't divide by one");
}
?>
See also Exceptions.
1.2.910.1. Specs¶
Short name |
Php/ThrowUsage |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.911. Throw Was An Expression¶
Throw used to be an expression. In PHP 7.0, there were some location where one couldn’t use a throw : this was the case for arrow functions, which expect one expression as function’s body.
Using throw as an instruction makes the code incompatible with PHP 7 version and older.
<?php
// Valid in PHP 8.0 and more recent
$fn = fn($a) => throw new Exception($a);
?>
See also Throw Expression and Exceptions.
1.2.911.1. Specs¶
Short name |
Php/ThrowWasAnExpression |
Rulesets |
CE, CompatibilityPHP72, CompatibilityPHP73, CompatibilityPHP74, All |
Exakat since |
2.1.1 |
PHP Version |
8.0+ |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.912. Too Many Native Calls¶
Avoid stuffing too many PHP native call inside another functioncall.
For readability reasons, or, more often, for edge case handling, it is recommended to avoid nesting too many PHP native calls.
This analysis reports any situation where more than 3 PHP native calls are nested.
<?php
// Too many nested functions
$cleanArray = array_unique(array_keys(array_count_values(array_column($source, 'x'))));
// Avoid warning when source is empty
$extract = array_column($source, 'x');
if (empty($extract)) {
$cleanArray = array();
} else {
$cleanArray = array_unique(array_keys(array_count_values($extract)));
}
// This is not readable, although it is short.
// It may easily get out of hand.
echo chr(80), chr(72), chr(80), chr(32), ' is great!';
?>
Name |
Default |
Type |
Description |
nativeCallCounts |
3 |
integer |
Number of native calls found inside another call. |
1.2.912.1. Specs¶
Short name |
Php/TooManyNativeCalls |
Rulesets |
|
Exakat since |
1.1.10 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.913. Trailing Comma In Calls¶
The last argument may be left empty.
This feature was introduced in PHP 7.3.
<?php
// VCS friendly call
// PHP 7.3 and more recent
foo(1,
2,
3,
);
// backward compatible call
// All PHP versions
foo(1,
2,
3
);
?>
See also PHP RFC: Allow a trailing comma in function calls.
1.2.913.1. Specs¶
Short name |
Php/TrailingComma |
Rulesets |
Appinfo, CE, CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, CompatibilityPHP70, CompatibilityPHP71, CompatibilityPHP72, All |
Exakat since |
1.4.0 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.914. Trigger Errors¶
List of situations where user errors are triggered.
PHP errors are triggered with trigger_error().
<?php
if ($divisor == 0) {
trigger_error('Cannot divide by zero', E_USER_ERROR);
}
?>
See also trigger_error.
1.2.914.1. Specs¶
Short name |
Php/TriggerErrorUsage |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.915. Caught Expressions¶
List of caught exceptions.
<?php
// This analyzer reports MyException and Exception
try {
doSomething();
} catch (MyException $e) {
fixIt();
} catch (\Exception $e) {
fixIt();
}
?>
See also and Exceptions.
1.2.915.1. Specs¶
Short name |
Php/TryCatchUsage |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
|
Time To Fix |
Slow (1 hour) |
Precision |
Very high |
Available in |
1.2.916. Try With Multiple Catch¶
Try may be used with multiple catch clauses.
<?php
try {
OneCatch();
} catch (FirstException $e) {
}
try {
TwoCatches();
} catch (FirstException $e) {
} catch (SecondException $e) {
}
?>
See also Exceptions.
1.2.916.1. Specs¶
Short name |
Php/TryMultipleCatch |
Rulesets |
|
Exakat since |
0.11.3 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.917. Typed Property Usage¶
PHP properties may be typed. Since PHP 7.4, it is possible to type properties, just like arguments and return values.
<?php
class User {
public int $id;
public string $name;
public function __construct(int $id, string $name) {
$this->id = $id;
$this->name = $name;
}
}
?>
1.2.917.2. Specs¶
Short name |
Php/TypedPropertyUsage |
Rulesets |
Appinfo, CE, CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, CompatibilityPHP70, CompatibilityPHP71, CompatibilityPHP72, CompatibilityPHP73, All |
Exakat since |
1.6.2 |
PHP Version |
7.4+ |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Available in |
1.2.918. Unicode Escape Partial¶
PHP 7 introduces a new escape sequence for strings : u{hex}. It is backward incompatible with previous PHP versions for two reasons :
PHP 7 will recognize en replace those sequences, while PHP 5 keep them intact. PHP 7 will halt on partial Unicode Sequences, as it tries to understand them, but may fail.
<?php
echo \u{1F418}\n;
// PHP 5 displays the same string
// PHP 7 displays : an elephant
echo \u{NOT A UNICODE CODEPOINT}\n;
// PHP 5 displays the same string
// PHP 7 emits a fatal error
?>
Is is recommended to check all those strings, and make sure they will behave correctly in PHP 7.
1.2.918.1. Specs¶
Short name |
Php/UnicodeEscapePartial |
Rulesets |
CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, All |
Exakat since |
0.8.4 |
PHP Version |
7.0- |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.919. Unicode Escape Syntax¶
Usage of the Unicode Escape syntax, with the
\u{xxxxx}format, available since PHP 7.0.
<?php
// Produce an elephant icon in PHP 7.0+
echo \u{1F418};
// Produce the raw sequence in PHP 5.0
echo \u{1F418};
?>
See also PHP RFC: Unicode Codepoint Escape Syntax, Code point and Unicode.
1.2.919.1. Specs¶
Short name |
Php/UnicodeEscapeSyntax |
Rulesets |
CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, All |
Exakat since |
0.8.4 |
PHP Version |
7.0+ |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.920. Unknown Pcre2 Option¶
PCRE2supports different options, compared toPCRE1.PCRE2was adopted with PHP 7.3.
The S modifier : it used to tell PCRE to spend more time studying the regex, so as to be faster at execution. This is now the default behavior, and may be dropped from the regex.
The X modifier : X is still existing with PCRE2, though it is now the default for PCRE2, and not for PHP as time of writing. In particular, Any backslash in a pattern that is followed by a letter that has no special meaning causes an error, thus reserving these combinations for future expansion. ``. It is recommended to avoid using useless sequence \s in regex to get ready for that change. All the following letters ``gijkmoqyFIJMOTY . Note that clLpPuU are valid PRCE sequences, and are probably failing for other reasons.
<?php
// \y has no meaning. With X option, this leads to a regex compilation error, and a failed test.
preg_match('/ye\y/', $string);
preg_match('/ye\y/X', $string);
?>
See also Pattern Modifiers and PHP RFC: PCRE2 migration.
1.2.920.1. Specs¶
Short name |
Php/UnknownPcre2Option |
Rulesets |
|
Exakat since |
1.0.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.921. Unpacking Inside Arrays¶
The variadic operator is now available inside arrays. Until PHP 7.4, it is not possible to use the variadic operator, or
...inside arrays.
The workaround is to use array_merge(), after checking that arrays are not empty.
<?php
$a = ['a', 'b', 'c'];
$b = ['d', 'e', 'f'];
// PHP 7.4
$c = [...$a, ...$b];
// PHP 7.3 and older
$c = array_merge($a, $b);
?>
1.2.921.1. Suggestions¶
Replace array_merge() with
....
1.2.921.2. Specs¶
Short name |
Php/UnpackingInsideArrays |
Rulesets |
CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, CompatibilityPHP70, CompatibilityPHP71, CompatibilityPHP72, CompatibilityPHP73, All |
Exakat since |
1.8.0 |
PHP Version |
7.4+ |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.922. Unset() Or (unset)¶
Unset() and (unset) have the same functional use.
The analyzed code has less than 10% of one of them : for consistency reasons, it is recommended to make them all the same.
It happens that unset() or (unset) are used depending on coding style and files. One file may be consistently using unset(), while the others are all using (unset).
<?php
// be consistent
(unset) $a1;
(unset) $a2;
(unset) $a3;
(unset) $a4;
(unset) $a5;
(unset) $a6;
(unset) $a7;
(unset) $a8;
(unset) $a9;
(unset) $a10;
(unset) $a11;
(unset) $a12;
unset($b);
?>
1.2.922.1. Specs¶
Short name |
Php/UnsetOrCast |
Rulesets |
|
Exakat since |
0.9.3 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.923. Unusual Case For PHP Functions¶
Usually, PHP functions are written all in lower case.
<?php
// All uppercases PHP functions
ECHO STRTOLOWER('This String');
?>
1.2.923.1. Specs¶
Short name |
Php/UpperCaseFunction |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.924. Non-lowercase Keywords¶
The usual convention is to write PHP keywords (like
as,foreach,switch,case,break, etc.) all in lowercase.
<?php
// usual PHP convention
foreach($array as $element) {
echo $element;
}
// unusual PHP conventions
Foreach($array AS $element) {
eCHo $element;
}
?>
PHP understands them in lowercase, UPPERCASE or WilD Case, so there is nothing compulsory here. Although, it will look strange to many.
Some keywords are missing from this analysis : extends, implements, as. This is due to the internal engine, which doesn’t keep track of them in its AST representation.
1.2.924.1. Suggestions¶
Use lowercase only PHP keywords, except for constants such as __CLASS__.
1.2.924.2. Specs¶
Short name |
Php/UpperCaseKeyword |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.925. Use PHP Attributes¶
PHP 8.0 attributes in use.
<?php
#[foo(4)]
class x {
}
?>
See also PHP RFC: Shorter Attribute Syntax, Attributes Amendements and Shorter Attribute Syntax Change.
1.2.925.1. Specs¶
Short name |
Php/UseAttributes |
Rulesets |
|
Exakat since |
2.1.6 |
PHP Version |
With PHP 8.0 and more recent |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Available in |
1.2.926. Use Browscap¶
Browscap is a browser database, accessible via get_browser().
Browscap is the ‘Browser Capabilities Project’.
<?php
echo $_SERVER['HTTP_USER_AGENT'] . \n\n;
$browser = get_browser(null, true);
print_r($browser);
?>
See also browscap.
1.2.926.1. Specs¶
Short name |
Php/UseBrowscap |
Rulesets |
|
Exakat since |
0.11.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.927. Use Cli¶
Signal the usage of code in CLI mode, through the usage of $argv and $argc variables.
<?php
// Characteristics of CLI usage
getopt(abcd);
?>
1.2.927.1. Specs¶
Short name |
Php/UseCli |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.928. Use Contravariance¶
Since a children class may accept a parent class of the argynebt type, the evolution is in opposite order.
Contravariance is a PHP 7.4 feature. Contravariance is distinct from return type covariance.
<?php
class X {
function m(Y $z): X {}
}
// m is overwriting the parent's method.
// The return type is different.
// The return type is compatible, as Y is also a sub-class of X.
class Y extends X {
function m(X $z): Y {}
}
?>
See also Covariant Returns and Contravariant Parameters and Php/UseCovariance.
1.2.928.1. Specs¶
Short name |
Php/UseContravariance |
Rulesets |
|
Exakat since |
1.9.3 |
PHP Version |
With PHP 7.4 and more recent |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Available in |
1.2.929. Use Cookies¶
This code source uses cookies.
Cookie usage is spotted with the usage of setcookie(), setrawcookie() and header() with the ‘Set-Cookie’ header.
<?php
header('Set-Cookie: '.$name.'='.$value.'; EXPIRES'.$date.';');
// From the PHP Manual :
setcookie('TestCookie3', $value, time()+3600, '/~rasmus/', 'example.com', 1);
?>
See also and Cookies.
1.2.929.1. Specs¶
Short name |
Php/UseCookies |
Rulesets |
|
Exakat since |
0.10.6 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.930. Use Covariance¶
Covariance is compatible return typehint. A child class may return an object of a child class of the return type of its parent’s method.
Since a children class may return a children class of the return type, the evolution is in the same order.
Covariance is a PHP 7.4 feature. Covariance is distinct from argument contravariance.
<?php
class X {
function m(Y $z): X {}
}
// m is overwriting the parent's method.
// The return type is different.
// The return type is compatible, as Y is also a sub-class of X.
class Y extends X {
function m(X $z): Y {}
}
?>
- See also Covariant Returns and Contravariant Parameters and
Php/UseContravariance.
1.2.930.1. Specs¶
Short name |
Php/UseCovariance |
Rulesets |
|
Exakat since |
1.9.3 |
PHP Version |
7.4+ |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.931. Use DateTimeImmutable Class¶
The DateTimeImmutable <https://www.php.net/`DateTimeImmutable>`_ class is the immutable version of the Datetime class.
While DateTime <https://www.php.net/`DateTime>`_ may be modified ‘in situ’, DateTimeImmutable cannot be modified. Any modification to such an object will return a new and distinct object. This avoid interferences that are hard to track.
<?php
// Example extracted from Derick Rethans' article (link below)
function formatNextMondayFromNow( DateTime $dt )
{
return $dt->modify( 'next monday' )->format( 'Y-m-d' );
}
$d = new DateTime(); //2014-02-17
echo formatNextMondayFromNow( $d ), \n;
echo $d->format( 'Y-m-d' ), \n; //2014-02-17
?>
See also What’s all this ‘immutable date’ stuff, anyway?, DateTimeImmutable, The `DateTime <https://www.php.net/`DateTime>`_ class <https://www.php.net/manual/en/class.datetime.php>`_ and The `DateTimeImmutable <https://www.php.net/`DateTimeImmutable>`_ class <https://www.php.net/manual/en/class.datetimeimmutable.php>`_.
1.2.931.1. Suggestions¶
Always use DateTimeImmutable when manipulating dates.
1.2.931.2. Specs¶
Short name |
Php/UseDateTimeImmutable |
Rulesets |
|
Exakat since |
1.8.7 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.932. Use get_debug_type()¶
get_debug_type() returns the given type of a variable. It was introduced in PHP 8.0.
<?php
// From the RFC
throw new TypeError('Expected ' . Foo::class . ' got ' . (is_object($bar) ? get_class($bar) : gettype($bar)));
// Becomes
throw new TypeError('Expected ' . Foo::class . ' got ' . get_debug_type($bar));
?>
See also PHP RFC: get_debug_type.
1.2.932.1. Suggestions¶
Replace the ternary with a call to get_debug_type()
1.2.932.2. Specs¶
Short name |
Php/UseGetDebugType |
Rulesets |
|
Exakat since |
2.1.9 |
PHP Version |
8.0+ |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Medium |
Available in |
1.2.933. Uses PHP 8 Match()¶
Use the match() syntax.
<?php
$A = match($a) {
'a' => 'A',
'b' => 'B',
default => 'd',
};
?>
See also match Match expression.
1.2.933.1. Specs¶
Short name |
Php/UseMatch |
Rulesets |
|
Exakat since |
2.1.4 |
PHP Version |
8.0+ |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Available in |
1.2.934. Use NullSafe Operator¶
The nullsafe operator
?->is an alternative to the object operator->. It silently fails the whole expression if a null is used for object.
<?php
$o = null;
// PHP 8.0 Failsafe : $r = null;
$r = $o->method();
// PHP 7.4- : Call to a member function method() on null
$r = $o->method();
?>
See also PHP RFC: Nullsafe operator.
1.2.934.1. Specs¶
Short name |
Php/UseNullSafeOperator |
Rulesets |
|
Exakat since |
2.1.6 |
PHP Version |
8.0+ |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.935. Use Nullable Type¶
The code uses nullable type, available since PHP 7.1.
Nullable Types are an option to type hint : they allow the passing value to be null, or another type.
According to the authors of the feature : ‘It is common in many programming languages including PHP to allow a variable to be of some type or null. This null often indicates an error or lack of something to return.’
<?php
function foo(?string $a = 'abc') : ?string {
return $a.b;
}
?>
See also Type declarations and PHP RFC: Nullable Types.
1.2.935.1. Specs¶
Short name |
Php/UseNullableType |
Rulesets |
Appinfo, CE, CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, CompatibilityPHP70, All |
Exakat since |
0.8.4 |
PHP Version |
7.1+ |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Available in |
1.2.936. Use PHP Object API¶
OOP API is the modern version of the PHP API.
When PHP offers the alternative between procedural and OOP api for the same features, it is recommended to use the OOP API.
Often, this least to more compact code, as methods are shorter, and there is no need to bring the resource around. Lots of new extensions are directly written in OOP form too.
OOP / procedural alternatives are available for mysqli <https://www.php.net/manual/en/book.`mysqli.php>`_, tidy <https://www.php.net/manual/en/book.`tidy.php>`_, cairo, finfo, and some others.
<?php
/// OOP version
$mysqli = new mysqli(localhost, my_user, my_password, world);
/* check connection */
if ($mysqli->connect_errno) {
printf(Connect failed: %s\n, $mysqli->connect_error);
exit();
}
/* Create table doesn't return a resultset */
if ($mysqli->query(CREATE TEMPORARY TABLE myCity LIKE City) === TRUE) {
printf(Table myCity successfully created.\n);
}
/* Select queries return a resultset */
if ($result = $mysqli->query(SELECT Name FROM City LIMIT 10)) {
printf(Select returned %d rows.\n, $result->num_rows);
/* free result set */
$result->close();
}
?>
<?php
/// Procedural version
$link = mysqli_connect(localhost, my_user, my_password, world);
/* check connection */
if (mysqli_connect_errno()) {
printf(Connect failed: %s\n, mysqli_connect_error());
exit();
}
/* Create table doesn't return a resultset */
if (mysqli_query($link, CREATE TEMPORARY TABLE myCity LIKE City) === TRUE) {
printf(Table myCity successfully created.\n);
}
?>
1.2.936.1. Suggestions¶
Use the object API
1.2.936.2. Specs¶
Short name |
Php/UseObjectApi |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
ClearPHP |
|
Examples |
|
Available in |
1.2.937. Use Pathinfo¶
Use pathinfo() function instead of string manipulations.
pathinfo() is more efficient and readable and string functions.
<?php
$filename = '/path/to/file.php';
// With pathinfo();
$details = pathinfo($filename);
print $details['extension']; // also capture php
// With string functions (other solutions possible)
$ext = substr($filename, - strpos(strreverse($filename), '.')); // Capture php
?>
When the path contains UTF-8 characters, pathinfo() may strip them. There, string functions are necessary.
1.2.937.1. Suggestions¶
Use pathinfo() and its second argument
1.2.937.2. Specs¶
Short name |
Php/UsePathinfo |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.938. Use pathinfo() Arguments¶
pathinfo() has a second argument to select only useful data.
It is twice faster to get only one element from pathinfo() than get the four of them, and use only one.
This analysis reports pathinfo() usage, without second argument, where only one or two indices are used, after the call.
<?php
// This could use only PATHINFO_BASENAME
function foo_db() {
$a = pathinfo($file2);
return $a['basename'];
}
// This could be 2 calls, with PATHINFO_BASENAME and PATHINFO_DIRNAME.
function foo_de() {
$a = pathinfo($file3);
return $a['dirname'].'/'.$a['basename'];
}
// This is OK : 3 calls to pathinfo() is slower than array access.
function foo_deb() {
$a = pathinfo($file4);
return $a['dirname'].'/'.$a['filename'].'.'.$a['extension'];
}
?>
Depending on the situation, the functions dirname() and basename() may also be used. They are even faster, when only fetching those data.
See also list.
1.2.938.1. Suggestions¶
Use PHP native function pathinfo() and its arguments
1.2.938.2. Specs¶
Short name |
Php/UsePathinfoArgs |
Rulesets |
|
Exakat since |
0.12.12 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.939. Use session_start() Options¶
It is possible to set the session’s option at session_start() call, skipping the usage of session_option().
This way, session’s options are set in one call, saving several hits.
This is available since PHP 7.0. It is recommended to set those values in the php.ini file, whenever possible.
<?php
// PHP 7.0
session_start(['session.name' => 'mySession',
'session.cookie_httponly' => 1,
'session.gc_maxlifetime' => 60 * 60);
// PHP 5.6- old way
ini_set ('session.name', 'mySession');
ini_set(session.cookie_httponly, 1);
ini_set('session.gc_maxlifetime', 60 * 60);
session_start();
?>
1.2.939.1. Suggestions¶
Use session_start() with array arguments
1.2.939.2. Specs¶
Short name |
Php/UseSessionStartOptions |
Rulesets |
|
Exakat since |
0.11.8 |
PHP Version |
7.0+ |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Examples |
|
Available in |
1.2.940. Should Use SetCookie()¶
Use setcookie() or setrawcookie(). Avoid using header() to do so, as the PHP native functions are more convenient and easier to spot during a refactoring.
setcookie() applies some encoding internally, for the value of the cookie and the date of expiration. Rarely, this encoding has to be skipped : then, use setrawencoding().
Both functions help by giving a checklist of important attributes to be used with the cookie.
<?php
// same as below
setcookie(myCookie, 'chocolate', time()+3600, /, , true, true);
// same as above. Slots for path and domain are omitted, but should be used whenever possible
header('Set-Cookie: myCookie=chocolate; Expires='.date('r', (time()+3600)).'; Secure; HttpOnly');
?>
See also Set-Cookie, setcookie.
1.2.940.1. Suggestions¶
Use setcookie() function, instead of header()
Use setcookie() function, instead of header()
1.2.940.2. Specs¶
Short name |
Php/UseSetCookie |
Rulesets |
|
Exakat since |
0.10.6 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.941. Avoid Using stdClass¶
stdClassis the default class for PHP. It is instantiated when PHP needs to return a object, but no class is specifically available.
It is recommended to avoid instantiating this class, nor use it is any way.
<?php
$json = '{a:1,b:2,c:3}';
$object = json_decode($json);
// $object is a stdClass, as returned by json_decode
// Fast building of $o
$a = [];
$a['a'] = 1;
$a['b'] = 2;
$a['c'] = 3;
json_encode( (object) $a);
// Slow building of $o
$o = new stdClass();
$o->a = 1;
$o->b = 2;
$o->c = 3;
json_encode($o);
?>
If you need a stdClass object, it is faster to build it as an array, then cast it, than instantiate stdClass. This is a micro-optimisation.
1.2.941.1. Suggestions¶
Create a custom class to handle the properties
1.2.941.2. Specs¶
Short name |
Php/UseStdclass |
Rulesets |
|
Exakat since |
0.9.1 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.942. Use str_contains()¶
str_contains() checks if a string is within another one. It replaces a call to strpos() with a comparison.
<?php
if (str_contains(abc, a)) { doSomething(); }
// strpos is used only for detection.
if (strpos(abc, a) !== false) { doSomething(); }
// strpos returns a position,
$pos = strpos(abca, a, 3);
if ($pos > 3) { doSomething();
?>
Note that this function is case sensitive : it cannot replace stripos().
Note that this function is single-byte only : it cannot replace mb_strpos().
This analysis omits calls to strpos() that are saved to a variable. strpos() is actually returning the position of the found string in the haystack, which may be reused later.
See also PHP RFC: str_contains.
1.2.942.1. Suggestions¶
Switch to str_contains()
1.2.942.2. Specs¶
Short name |
Php/UseStrContains |
Rulesets |
|
Exakat since |
2.2.0 |
PHP Version |
8.0+ |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.943. Use Closure Trailing Comma¶
Use a trailing comma in the closure’s use list. This feature was added in PHP 8.0.
<?php
// PHP 8.0 valid syntax
$f = function foo() use ($a, ) { };
// always valid syntax for closure
$f = function foo() use ($a ) { };
?>
See also Trailing Comma In `Closure Use List <https://wiki.php.net/rfc/trailing_comma_in_closure_use_list>`_.
1.2.943.1. Specs¶
Short name |
Php/UseTrailingUseComma |
Rulesets |
|
Exakat since |
2.1.6 |
PHP Version |
8.0+ |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.944. Use Web¶
The code is used in web environment.
The web usage is identified through the usage of the superglobals.
<?php
// Accessing $_GET is possible when PHP is used in a web server.
$x = filter_validate($_GET['x'], FILTER_EMAIL);
?>
1.2.944.1. Specs¶
Short name |
Php/UseWeb |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.945. Uses Environment¶
<?php
// Take some configuration from the environment
$secret_key = getenv('secret_key');
?>
1.2.945.1. Specs¶
Short name |
Php/UsesEnv |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.946. Usort Sorting In PHP 7.0¶
If this sorting is important, it is advised to add extra comparison in the user-function and avoid returning 0 (thus, depending on default implementation).
<?php
$a = [ 2, 4, 3, 6];
function noSort($a) { return $a > 5; }
usort($a, 'noSort');
print_r($a);
?>
In PHP 5, the results is ::
Array
(
[0] => 3
[1] => 4
[2] => 2
[3] => 6
)
in PHP 7, the result is ::
Array
(
[0] => 2
[1] => 4
[2] => 3
[3] => 6
)
1.2.946.1. Suggestions¶
Make sure the sorting function doesn’t generate any ex-aequos.
1.2.946.2. Specs¶
Short name |
Php/UsortSorting |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
Medium |
Available in |
1.2.947. Wrong Attribute Configuration¶
A class is attributed to the wrong PHP structure.
<?php
#[Attribute(Attribute::TARGET_CLASS)]
class ClassAttribute { }
// Wrong
#[ClassAttribute]
function foo () {}
// OK
#[ClassAttribute]
class y {}
?>
1.2.947.1. Suggestions¶
Remove the attribute from the wrongly attributed structure
Extend the configuration of the attribute with Attribute::TARGET_*
See also and Declaring Attribute Classes.
1.2.947.2. Specs¶
Short name |
Php/WrongAttributeConfiguration |
Rulesets |
|
Exakat since |
2.2.0 |
PHP Version |
With PHP 8.0 and more recent |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.948. Wrong Type For Native PHP Function¶
This analysis reports calls to a PHP native function with a wrongly typed value.
<?php
// valid calls
echo exp(1);
echo exp(2.5);
// invalid calls
echo exp(1);
echo exp(array(2.5));
// valid call, but invalid math
// -1 is not a valid value for log(), but -1 is a valid type (int) : it is not reported by this analysis.
echo log(-1);
?>
1.2.948.1. Suggestions¶
Set the code to the valid type, when calling a PHP native function
1.2.948.2. Specs¶
Short name |
Php/WrongTypeForNativeFunction |
Rulesets |
|
Exakat since |
2.1.5 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.949. Yield From Usage¶
Usage of generator delegation, with
yield fromkeyword.
In PHP 7, generator delegation allows you to yield values from another Generator, Traversable object, or array by using the yield from.
Yield from was introduced in PHP 7.1, and is backward incompatible.
<?php
// Yield delegation
function foo() {
yield from bar();
}
function bar() {
yield 1;
}
?>
See also Generator Syntax and Understanding PHP Generators.
1.2.949.1. Specs¶
Short name |
Php/YieldFromUsage |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
7.0+ |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.950. Yield Usage¶
Usage of generators, with yield keyword.
Yield was introduced in PHP 5.5, and is backward incompatible.
<?php
function prime() {
$primes = [2, 3, 5, 7, 11, 13, 17, 19];
foreach($primes as $prime) {
yield $prime;
}
}
?>
See also Generator Syntax, Deal with Memory Gently using Yield in PHP and Understanding PHP Generators.
1.2.950.1. Specs¶
Short name |
Php/YieldUsage |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
5.5+ |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.951. __debugInfo() Usage¶
The magic method __debugInfo() provides a custom way to dump an object.
It has been introduced in PHP 5.6. In the previous versions of PHP, this method is ignored and won’t be called when debugging.
<?php
// PHP 5.6 or later
class foo {
private $bar = 1;
private $reallyHidden = 2;
function __debugInfo() {
return ['bar' => $this->bar,
'reallyHidden' => 'Secret'];
}
}
$f = new Foo();
var_dump($f);
/* Displays :
object(foo)#1 (2) {
[bar]=>
int(1)
[reallyHidden]=>
string(6) Secret
}
*/
?>
See also Magic methods.
1.2.951.1. Specs¶
Short name |
Php/debugInfoUsage |
Rulesets |
CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, All |
Exakat since |
0.8.4 |
PHP Version |
5.6+ |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Examples |
|
Available in |
1.2.952. Old Style __autoload()¶
Avoid __autoload(), only use spl_register_autoload().
__autoload() is deprecated since PHP 7.2 and possibly removed in later versions. spl_register_autoload() was introduced in PHP 5.1.0.
__autoload() may only be declared once, and cannot be modified later. This creates potential conflicts between libraries that try to set up their own autoloading schema.
On the other hand, spl_register_autoload() allows registering and de-registering multiple autoloading functions or methods.
<?php
// Modern autoloading.
function myAutoload($class){}
spl_register_autoload('myAutoload');
// Old style autoloading.
function __autoload($class){}
?>
Do not use the old __autoload() function, but rather the new spl_register_autoload() function.
See also Autoloading Classe.
1.2.952.1. Suggestions¶
Move to spl_register_autoload()
Remove usage of the old __autoload() function
Modernize usage of old libraries
1.2.952.2. Specs¶
Short name |
Php/oldAutoloadUsage |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Instant (5 mins) |
Precision |
High |
ClearPHP |
|
Examples |
|
Available in |
1.2.953. Fopen Binary Mode¶
Use explicit
bwhen opening files.
fopen() supports a b option in the second parameter, to make sure the read is binary. This is the recommended way when writing portable applications, between Linux and Windows.
<?php
// This opens file with binary reads on every OS
$fp = fopen('path/to/file.doc', 'wb');
// This may not open files with binary mode on Windows
$fp = fopen('path/to/file.doc', 'w');
?>
Also, Windows PHP does support a t option, that translates automatically line endings to the right value. As this is Windows only, this should be avoided for portability reasons.
See also fopen.
1.2.953.1. Specs¶
Short name |
Portability/FopenMode |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.954. GLOB_BRACE Usage¶
GLOB_BRACE is not always available. This is the case on Solaris OS, and on Alpine OS, used for Docker.
<?php
// glob uses GLOB_BRACE
$abcFiles = glob($path.'/{a,b,c}*', GLOB_BRACE);
// avoiding usage of GLOB_BRACE
$abcFiles = array_merge(glob($path.'/a*'),
glob($path.'/b*'),
glob($path.'/c*'),
);
?>
It is possible to check the support for GLOB_BRACE by checking the presence of the constant.
See also Alpine Linux and GLOB_BRACE breaks Sulu on Alpine Linux.
1.2.954.1. Suggestions¶
Create as many glob() calls at there are alternative in the braces
1.2.954.2. Specs¶
Short name |
Portability/GlobBraceUsage |
Rulesets |
|
Exakat since |
2.1.6 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.955. Iconv With Translit¶
The transliteration feature of iconv() depends on the underlying system to support it.
<?php
$string = iconv('utf-8', 'utf-8//TRANSLIT', $source);
?>
See also iconv().
1.2.955.1. Suggestions¶
Use an OS that supports TRANSLIT with iconv
Remove the usage of TRANSLIT
1.2.955.2. Specs¶
Short name |
Portability/IconvTranslit |
Rulesets |
|
Exakat since |
2.1.6 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.956. Linux Only Files¶
List of files that are only found on Linux style systems. They are making the application depend on the system.
<?php
// Really non-portable system check
$os = shell_exec(cat /proc/version);
echo You are using $os\n;
?>
1.2.956.1. Specs¶
Short name |
Portability/LinuxOnlyFiles |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.957. Windows Only Constants¶
When built on Windows, PHP offers some extra constants. They are not available on other operating systems.
<?php
//The Windows build number (for example, Windows Vista with SP1 applied is build 6001)
echo PHP_WINDOWS_VERSION_BUILD;
?>
See also Info Predefined Constants.
1.2.957.1. Specs¶
Short name |
Portability/WindowsOnlyConstants |
Rulesets |
none |
Exakat since |
1.7.0 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.958. Is Library¶
Is this project a library (it must be used in a larger project) or a standalone code.
1.2.958.1. Specs¶
Short name |
Project/IsLibrary |
Rulesets |
none |
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.959. PSR-11 Usage¶
PSR-11 describes a common interface for dependency injection containers.
It is supported by an set of interfaces, that one may use in the code.
<?php
namespace MyNamespace;
// MyContainerInterface implements the PSR-7 ServerRequestInterface.
// MyContainerInterface is more of a black hole than a real Container.
class MyContainerInterface implements \Psr\Container\ContainerInterface {
public function get($id) {}
public function has($id) {}
}
?>
See also PSR-11 : Dependency injection container.
1.2.959.1. Specs¶
Short name |
Psr/Psr11Usage |
Rulesets |
|
Exakat since |
0.11.5 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.960. PSR-13 Usage¶
PSR-13 describes a common interface for dependency injection containers.
It is supported by an set of interfaces, that one may use in the code.
<?php
namespace MyNamespace;
// MyLink implements the PSR-13 LinkInterface.
// MyLink is more of a black hole than a real Container.
class MyLink implements LinkInterface {
public function getHref() {}
public function isTemplated() {}
public function getRels() {}
public function getAttributes() {}
}
?>
See also PSR-13 : Link definition interface.
1.2.960.1. Specs¶
Short name |
Psr/Psr13Usage |
Rulesets |
|
Exakat since |
0.11.6 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.961. PSR-16 Usage¶
PSR-16 describes a simple yet extensible interface for a cache item and a cache driver. It is supported by an set of interfaces, that one may use in the code.
<?php
namespace My\SimpleCache;
// MyCache implements the PSR-16 Simple cache.
// MyCache is more of a black hole than a real cache.
class MyCache implements Psr\SimpleCache\CacheInterface {
public function get($key, $default = null) {}
public function set($key, $value, $ttl = null) {}
public function delete($key) {}
public function clear() {}
public function getMultiple($keys, $default = null) {}
public function setMultiple($values, $ttl = null) {}
public function deleteMultiple($keys) {}
public function has($key) {}
}
?>
See also PSR-16 : Common Interface for Caching Libraries.
1.2.961.1. Specs¶
Short name |
Psr/Psr16Usage |
Rulesets |
|
Exakat since |
0.11.6 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.962. PSR-3 Usage¶
PSR-3 describes a common interface for logging libraries.
It is supported by an set of interfaces, that one may use in the code.
<?php
namespace MyNamespace;
// MyLog implements the PSR-3 LoggerInterface.
// MyLog is more of a black hole than a real Log.
namespace ;
class MyLog implements \Psr\Log\LoggerInterface {
public function emergency($message, array $context = array()) {}
public function alert($message, array $context = array()) {}
public function critical($message, array $context = array()) {}
public function error($message, array $context = array()) {}
public function warning($message, array $context = array()) {}
public function notice($message, array $context = array()) {}
public function info($message, array $context = array()) {}
public function debug($message, array $context = array()) {}
public function log($level, $message, array $context = array()) {}
}
?>
See also PSR-3 : Logger Interface.
1.2.962.1. Specs¶
Short name |
Psr/Psr3Usage |
Rulesets |
|
Exakat since |
0.11.6 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.963. PSR-6 Usage¶
PSR-6 is the cache standard for PHP.
The goal of PSR-6 is to allow developers to create cache-aware libraries that can be integrated into existing frameworks and systems without the need for custom development.
It is supported by an set of interfaces, that one may use in the code.
<?php
namespace MyNamespace;
// MyCacheItem implements the PSR-7 CacheItemInterface.
// This MyCacheItem is more of a black hole than a real CacheItem.
class MyCacheItem implements \Psr\Cache\CacheItemInterface {
public function getKey() {}
public function get() {}
public function isHit() {}
public function set($value) {}
public function expiresAt($expiration) {}
public function expiresAfter($time) {}
}
?>
See also PSR-6 : Caching.
1.2.963.1. Specs¶
Short name |
Psr/Psr6Usage |
Rulesets |
|
Exakat since |
0.11.6 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.964. PSR-7 Usage¶
It is supported by an set of interfaces, that one may use in the code.
<?php
namespace MyNamespace;
// MyServerRequest implements the PSR-7 ServerRequestInterface.
// MyServerRequest is more of a black hole than a real Server.
class MyServerRequest extends \Psr\Http\Message\ServerRequestInterface {
public function getServerParams() {}
public function getCookieParams() {}
public function withCookieParams(array $cookies) {}
public function getQueryParams() {}
public function withQueryParams(array $query) {}
public function getUploadedFiles() {}
public function withUploadedFiles(array $uploadedFiles) {}
public function getParsedBody() {}
public function withParsedBody($data) {}
public function getAttributes() {}
public function getAttribute($name, $default = null) {}
public function withAttribute($name, $value) {}
public function withoutAttribute($name) {}
}
?>
See also PSR-7 : HTTP message interfaces.
1.2.964.1. Specs¶
Short name |
Psr/Psr7Usage |
Rulesets |
|
Exakat since |
0.11.6 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.965. Always Anchor Regex¶
Unanchored regex finds the requested pattern, and leaves room for malicious content.
Without ^ and $, the regex searches for any pattern that satisfies the criteria, leaving any unused part of the string available for arbitrary content. It is recommended to use both anchor
<?php
$birthday = getSomeDate($_GET);
// Permissive version : $birthday = '1970-01-01<script>xss();</script>';
if (!preg_match('/\d{4}-\d{2}-\d{2}/', $birthday) {
error('Wrong data format for your birthday!');
}
// Restrictive version : $birthday = '1970-01-01';
if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $birthday) {
error('Wrong data format for your birthday!');
}
echo 'Your birthday is on '.$birthday;
?>
Note that $ may be a line ending, still leaving room after it for injection.
<?php
$birthday = '1970-01-01'.PHP_EOL.'<script>xss();</script>';
?>
This analysis reports false positive when the regex is used to search a pattern in a much larger string. Check if this rule doesn’t apply, though.
1.2.965.1. Suggestions¶
Add an anchor to the beginning and ending of the string
See also and CWE-625: Permissive Regular Expression.
1.2.965.2. Specs¶
Short name |
Security/AnchorRegex |
Rulesets |
|
Exakat since |
0.12.15 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.966. Avoid Those Hash Functions¶
The following cryptography algorithms are considered insecure, and should be replaced with new and more performant algorithms.
MD2, MD4, MD5, SHA0, SHA1, CRC, DES, 3DES, RC2, RC4.
When possible, avoid using them, may it be as PHP functions, or hashing function configurations (mcrypt, hash…).
<?php
// Weak cryptographic algorithm
echo md5('The quick brown fox jumped over the lazy dog.');
// Weak cryptographic algorthim, used with a modern PHP extension (easier to update)
echo hash('md5', 'The quick brown fox jumped over the lazy dog.');
// Strong cryptographic algorthim, used with a modern PHP extension
echo hash('sha156', 'The quick brown fox jumped over the lazy dog.');
?>
Weak cryptography is commonly used for hashing values when caching them. In such cases, security is not a primary concern. However, it may later become such, when hackers get access to the cache folders, or if the cached identifier is published. As a preventive protection, it is recommended to always use a secure hashing function.
1.2.966.1. Suggestions¶
Keep the current crypto, and add a call to a stronger one.
Change the crypto for a more modern one and update the related databases
See also and Secure Hash Algorithms.
1.2.966.2. Specs¶
Short name |
Security/AvoidThoseCrypto |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Available in |
1.2.967. Can’t Disable Class¶
This is the list of potentially dangerous PHP class being used in the code, such as Phar.
<?php
// This script uses ftp_connect(), therefore, this function shouldn't be disabled.
$phar = new Phar();
?>
This analysis is the base for suggesting values for the disable_classes directive.
1.2.967.2. Specs¶
Short name |
Security/CantDisableClass |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.968. Can’t Disable Function¶
This is the list of potentially dangerous PHP functions being used in the code, such as exec() or fsockopen().
eval() is not reported here, as it is not a PHP function, but a language construct : it can’t be disabled.
<?php
// This script uses ftp_connect(), therefore, this function shouldn't be disabled.
$ftp = ftp_connect($host, 21);
// This script doesn't use imap_open(), therefore, this function may be disabled.
?>
This analysis is the base for suggesting values for the disable_functions directive.
1.2.968.1. Specs¶
Short name |
Security/CantDisableFunction |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.969. Compare Hash¶
When comparing hash values, it is important to use the strict comparison : hash_equals(),
===or!==.
In a number of situations, the hash value will start with 0e, and PHP will understand that the comparison involves integers : it will then convert the strings into numbers, and it may end up converting them to 0.
Here is an example :
<?php
// The two following passwords hashes matches, while they are not the same.
$hashed_password = 0e462097431906509000000000000;
if (hash('md5','240610708',false) == $hashed_password) {
print 'Matched.'.PHP_EOL;
}
// hash returns a string, that is mistaken with 0 by PHP
// The strength of the hashing algorithm is not a problem
if (hash('ripemd160','20583002034',false) == '0') {
print 'Matched.'.PHP_EOL;
}
if (hash('md5','240610708',false) !== $hashed_password) {
print 'NOT Matched.'.PHP_EOL;
}
// Display true
var_dump(md5('240610708') == md5('QNKCDZO') );
?>
You may also use password_hash() and password_verify() : they work together without integer conversion problems, and they can’t be confused with a number.
See also Magic Hashes What is the best way to compare hashed strings? (PHP) and md5(‘240610708’) == md5(‘QNKCDZO’).
1.2.969.1. Suggestions¶
Use dedicated functions for hash comparisons
Use identity operators (===), and not equality operators (==) to compare hashes
Compare hashes in the database (or external system), where such confusion is not possible
1.2.969.2. Specs¶
Short name |
Security/CompareHash |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
ClearPHP |
|
Examples |
|
Available in |
1.2.970. Configure Extract¶
The extract() function overwrites local variables when left unconfigured.
Extract imports variables from an array into the local scope. In case of a conflict, that is when a local variable already exists, it overwrites the previous variable.
In fact, extract() may be configured to handle the situation differently : it may skip the conflicting variable, prefix it, prefix it only if it exists, only import overwriting variables… It may also import them as references to the original values.
This analysis reports extract() when it is not configured explicitly. If overwriting is the intended objective, it is not reported.
<?php
// ignore overwriting variables
extract($array, EXTR_SKIP);
// prefix all variables explicitly variables with 'php_'
extract($array, EXTR_PREFIX_ALL, 'php_');
// overwrites explicitly variables
extract($array, EXTR_OVERWRITE);
// overwrites implicitely variables : do we really want that?
extract($array, EXTR_OVERWRITE);
?>
Always avoid using extract() on untrusted sources, such as $_GET, $_POST, $_FILES, or even databases records.
See also extract.
1.2.970.1. Suggestions¶
Always use the second argument of extract(), and avoid using
EXTR_OVERWRITE
1.2.970.2. Specs¶
Short name |
Security/ConfigureExtract |
Rulesets |
|
Exakat since |
1.2.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.971. Check Crypto Key Length¶
Each cryptography algorithm requires a reasonable length. Make sure an up-to-date length is used.
This rule use the following recommendations :
`OPENSSL_KEYTYPE_RSA <https://www.php.net/OPENSSL_KEYTYPE_RSA>`_’ => 3072
`OPENSSL_KEYTYPE_DSA <https://www.php.net/OPENSSL_KEYTYPE_DSA>`_’ => 2048
`OPENSSL_KEYTYPE_DH <https://www.php.net/OPENSSL_KEYTYPE_DH>`_’ => 2048
`OPENSSL_KEYTYPE_EC <https://www.php.net/OPENSSL_KEYTYPE_EC>`_’ => 512
The values above are used with the openssl PHP extension.
<?php
// Extracted from the documentation
// Generates a new and strong key
$private_key = openssl_pkey_new(array(
private_key_type => OPENSSL_KEYTYPE_EC,
private_key_bits => 1024,
));
// Generates a new and weak key
$private_key = openssl_pkey_new(array(
private_key_type => OPENSSL_KEYTYPE_EC,
private_key_bits => 256,
));
?>
See also The Definitive 2019 Guide to Cryptographic Key Sizes and Algorithm Recommendations and Cryptographic Key Length Recommendation.
1.2.971.1. Suggestions¶
Lengthen the cryptographic key
1.2.971.2. Specs¶
Short name |
Security/CryptoKeyLength |
Rulesets |
|
Exakat since |
2.1.1 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.972. Safe Curl Options¶
It is advised to always use
CURLOPT_SSL_VERIFYPEERandCURLOPT_SSL_VERIFYHOSTwhen requesting a SSL connection.
With those tests, the certificate is verified, and if it isn’t valid, the connection fails : this is a safe behavior.
<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, https://www.php.net/);
// To be safe, always set this to true
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_exec($ch);
curl_close($ch);
?>
See also Don’t turn off `CURLOPT_SSL_VERIFYPEER, fix your PHP configuration <https://www.saotn.org/dont-turn-off-curlopt_ssl_verifypeer-fix-php-configuration/>`_, Certainty: Automated CACert.pem Management for PHP Software and Server-Side HTTPS Requests.
1.2.972.1. Suggestions¶
Always use CURLOPT_SSL_VERIFYPEER and HTTPS for communication with other servers
1.2.972.2. Specs¶
Short name |
Security/CurlOptions |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.973. Direct Injection¶
The following code act directly upon PHP incoming variables like
$_GETand$_POST. This makes those snippets very unsafe.
<?php
// Direct injection
echo Hello.$_GET['user']., welcome.;
// less direct injection
foo($_GET['user']);
function foo($user) {
echo Hello.$user., welcome.;
}
?>
See also Cross-Site Scripting (XSS)
1.2.973.1. Suggestions¶
Validate input : make sure the incoming data are what you expect from them.
Escape output : prepare outgoing data for the next system to use.
1.2.973.2. Specs¶
Short name |
Security/DirectInjection |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.974. Don’t Echo Error¶
It is recommended to avoid displaying error messages directly to the browser.
PHP’s uses the display_errors directive to control display of errors to the browser. This must be kept to off when in production.
<?php
// Inside a 'or' test
mysql_connect('localhost', $user, $pass) or die(mysql_error());
// Inside a if test
$result = pg_query( $db, $query );
if( !$result )
{
echo Erreur SQL: . pg_error();
exit;
}
// Changing PHP configuration
ini_set('display_errors', 1);
// This is also a security error : 'false' means actually true.
ini_set('display_errors', 'false');
?>
Error messages should be logged, but not displayed.
See also Error reporting and List of php.ini directives.
1.2.974.1. Suggestions¶
Remove any echo, print, printf() call built with error messages from an exception, or external source.
1.2.974.2. Specs¶
Short name |
Security/DontEchoError |
Rulesets |
|
Exakat since |
0.8.7 |
PHP Version |
All |
Severity |
Critical |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.975. Dynamic Library Loading¶
Loading a variable dynamically requires a lot of care in the preparation of the library name.
In case of injection in the variable, the dynamic loading of a library gives a lot of power to an intruder.
<?php
// dynamically loading a library
dl($library. PHP_SHLIB_SUFFIX);
// dynamically loading ext/vips
dl('vips.' . PHP_SHLIB_SUFFIX);
// static loading ext/vips (unix only)
dl('vips.so');
?>
See also dl.
1.2.975.1. Suggestions¶
Use a switch structure, to make the dl() calls static.
Avoid using dl() and make the needed extension always available in PHP binary.
1.2.975.2. Specs¶
Short name |
Security/DynamicDl |
Rulesets |
|
Exakat since |
1.1.7 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.976. Encoded Simple Letters¶
Some simple letters are written in escape sequence.
Usually, escape sequences are made to encode unusual characters. Using escape sequences for simple characters, like letters or numbers is suspicious.
This analysis also detects Unicode codepoint with superfluous leading zeros.
<?php
// This escape sequence makes eval hard to spot
$a = ev\101l;
$a('php_info();');
// With a PHP 7.0 unicode code point sequence
$a = ev\u{000041}l;
$a('php_info();');
// With a PHP 5.0+ hexadecimal sequence
$a = ev\x41l;
$a('php_info();');
?>
1.2.976.1. Suggestions¶
Make all simple letter appear clearly
Add comments about why this code is encoded
1.2.976.2. Specs¶
Short name |
Security/EncodedLetters |
Rulesets |
|
Exakat since |
0.10.5 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.977. filter_input() As A Source¶
The filter_input() and filter_input_array() functions access directly to
$_GET. They represent a source for external data just like$_GET,$_POST, etc.
The main feature of filter_input() is that it is already filtered. The main drawback is that FILTER_FLAG_NONE is the none filter, and that default configuration is FILTER_UNSAFE_RAW.
The filter extension keeps access to the incoming data, even after the super globals, such as $_GET, are unset.
<?php
// Removing $_GET
$_GET = [];
// with the default : FILTER_UNSAFE_RAW, this means XSS
echo filter_input(INPUT_GET, 'i');
// Same as above :
echo filter_var(_GET, 'i');
?>
Thanks to Frederic Bouchery for reporting this special case.
See also Data filtering.
1.2.977.1. Suggestions¶
Use the classic $_GET, $_POST super globals, which are easier to audit.
Use your framework’s parameter access.
1.2.977.2. Specs¶
Short name |
Security/FilterInputSource |
Rulesets |
|
Exakat since |
1.4.8 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.978. GPRC Aliases¶
1.2.978.1. Specs¶
Short name |
Security/GPRAliases |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.979. Indirect Injection¶
<?php
$a = $_GET['a'];
echo $a;
function foo($b) {
echo $b;
}
foo($_POST['c']);
?>
1.2.979.1. Suggestions¶
Always validate incoming values before using them.
1.2.979.2. Specs¶
Short name |
Security/IndirectInjection |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Critical |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.980. Insecure Integer Validation¶
Comparing incoming variables to integer may lead to injection.
When comparing a variable to an integer, PHP applies type juggling, and transform the variable in an integer too. When the value converts smoothly to an integer, this means the validation may pass and yet, the value may carry an injection.
<?php
// This is safe :
if ($_GET['x'] === 2) {
echo $_GET['x'];
}
// Using (int) for validation and for display
if ((int) $_GET['x'] === 2) {
echo (int) $_GET['x'];
}
// This is an injection
// '2 <script>' == 2, then echo will make the injection
if ($_GET['x'] == 2) {
echo $_GET['x'];
}
// This is unsafe, as $_GET['x'] is tested as an integer, but echo'ed raw
if ((int) $_GET['x'] === 2) {
echo $_GET['x'];
}
?>
This analysis spots situations where an incoming value is compared to an integer. The usage of the validated value is not analyzed further.
1.2.980.1. Suggestions¶
Add the typecasting to all read access to the incoming variable
Add the typecasting when writing the incoming value to a local variable
See also Type Juggling Authentication Bypass Vulnerability in CMS Made Simple, PHP STRING COMPARISON VULNERABILITIES and PHP Magic Tricks: Type Juggling.
1.2.980.2. Specs¶
Short name |
Security/IntegerConversion |
Rulesets |
|
Exakat since |
1.7.7 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.981. Keep Files Access Restricted¶
Avoid using 0777 as file or directory mode. In particular, setting a file or a directory to 0777 (or universal read-write-execute) may lead to security vulnerabilities, as anything on the server may read, write and even execute
File mode may be changed using the chmod() function, or at directory creation, with mkdir().
<?php
file_put_contents($file, $content);
// this file is accessible to the current user, and to his group, for reading and writing.
chmod($file, 0550);
// this file is accessible to everyone
chmod($file, 0777);
?>
By default, this analysis report universal access (0777). It is possible to make this analysis more restrictive, by providing more forbidden modes in the filePrivileges parameter. For example : 511,510,489. Only use a decimal representation.
See also Mkdir Default and Least Privilege Violation.
1.2.981.1. Suggestions¶
Set the file mode to a level of restriction as low as possible.
Name |
Default |
Type |
Description |
filePrivileges |
0777 |
string |
List of forbidden file modes (comma separated). |
1.2.981.2. Specs¶
Short name |
Security/KeepFilesRestricted |
Rulesets |
|
Exakat since |
2.1.1 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.982. Minus One On Error¶
Some PHP native functions return -1 on error. They also return 1 in case of success, and 0 in case of failure. This leads to confusions.
In case the native function is used as a condition without explicit comparison, PHP type cast the return value to a boolean. In this case, -1 and 1 are both converted to true, and the condition applies. This means that an error situation is mistaken for a successful event.
<?php
// Proper check of the return value
if (openssl_verify($data, $signature, $public) === 1) {
$this->loginAsUser($user);
}
// if this call fails, it returns -1, and is confused with true
if (openssl_verify($data, $signature, $public)) {
$this->loginAsUser($user);
}
?>
This analysis searches for if/then structures, ternary operators inside while() / do…`while() <https://www.php.net/manual/en/control-structures.while.php>`_ loops.
See also Can you spot the vulnerability? (openssl_verify) and Incorrect Signature Verification.
1.2.982.1. Suggestions¶
Compare explicitly the return value to 1
1.2.982.2. Specs¶
Short name |
Security/MinusOneOnError |
Rulesets |
|
Exakat since |
1.8.0 |
PHP Version |
All |
Severity |
Critical |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.983. Mkdir Default¶
mkdir() gives universal access to created folders, by default. It is recommended to gives limited set of rights (0755, 0700), or to explicitly set the rights to 0777.
<?php
// By default, this dir is 777
mkdir('/path/to/dir');
// Explicitely, this is wanted. It may also be audited easily
mkdir('/path/to/dir', 0777);
// This dir is limited to the current user.
mkdir('/path/to/dir', 0700);
?>
See also Why 777 Folder Permissions are a Security Risk.
1.2.983.1. Suggestions¶
Always use the lowest possible privileges on folders
Don’t use the PHP default : at least, make it explicit that the ‘universal’ rights are voluntary
1.2.983.2. Specs¶
Short name |
Security/MkdirDefault |
Rulesets |
|
Exakat since |
0.12.2 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.984. move_uploaded_file Instead Of copy¶
Always use move_uploaded_file() with uploaded files. Avoid using copy or rename with uploaded file.
move_uploaded_file() checks to ensure that the file designated by filename is a valid upload file (meaning that it was uploaded via PHP’s HTTP POST upload mechanism).
<?php
// $a->file was filled with $_FILES at some point
move_uploaded_file($a->file['tmp_name'], $target);
// $a->file was filled with $_FILES at some point
rename($a->file['tmp_name'], $target);
?>
See also move_uploaded_file and Uploading Files with PHP.
1.2.984.1. Suggestions¶
Always use move_uploaded_file()
Extract the needed information from the file, and leave it for PHP to remove without storage
1.2.984.2. Specs¶
Short name |
Security/MoveUploadedFile |
Rulesets |
|
Exakat since |
1.3.2 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.985. No ENT_IGNORE¶
Certain characters have special significance in HTML, and should be represented by HTML entities if they are to preserve their meanings.
ENT_IGNORE is a configuration option for htmlspecialchars(), that ignore any needed character replacement. This mean the raw input will now be processed by PHP, or a target browser.
It is recommended to use the other configuration options : ENT_COMPAT, ENT_QUOTES, ENT_NOQUOTES, ENT_SUBSTITUTE, ENT_DISALLOWED, ENT_HTML401, ENT_XML1, ENT_XHTML or ENT_HTML5.
<?php
// This produces a valid HTML tag
$new = htmlspecialchars("<a href='test'>Test</a>", ENT_IGNORE);
echo $new; // <a href='test'>Test</a>
// This produces a valid string, without any HTML special value
$new = htmlspecialchars("<a href='test'>Test</a>", ENT_QUOTES);
echo $new; // <a href='test'>Test</a>
?>
See also htmlspecialchars and Deletion of Code Points.
1.2.985.1. Suggestions¶
Use of the the other options
1.2.985.2. Specs¶
Short name |
Security/NoEntIgnore |
Rulesets |
|
Exakat since |
1.9.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.986. No Net For Xml Load¶
Simplexml and ext/DOM load all external entities from the web, by default. This is dangerous, in particular when loading unknown XML code.
Look at this XML code below : it is valid. It defines an entity xxe, that is filled with a file, read on the system and base64 encoded.:
<!DOCTYPE replace [<!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=index.php"> ]>
<replace>&xxe;</replace>
This file could be processed with the following code : note, you can replace ‘index.php’ in the above entity by any valid filepath.
<?php
$dom = new DOMDocument();
$dom->loadXML($xml, LIBXML_NOENT | LIBXML_DTDLOAD);
$info = simplexml_import_dom($dom);
print base64_decode($info[0]);
?>
Here, PHP tries to load the XML file, finds the entity, then solves the entity by encoding a file called index.php. The source code of the file is not used as data in the XML file.
At that point, the example illustrates how a XXE works : by using the XML engine to load external resources, and preprocessing the XML code. in fact, there is only one change to make this XML code arbitrarily injected ::
<!DOCTYPE replace [<!ENTITY writer SYSTEM https://www.example.com/entities.dtd> ]>
<replace>&xxe;</replace>
With the above example, the XML code is static (as, it never changes), but the ‘xxe’ definitions are loaded from a remove website, and are completely under the attacker control.
See also XML External Entity, XML External Entity (XXE) Processing and Detecting and exploiting XXE in SAML Interfaces.
1.2.986.1. Suggestions¶
Strip out any entity when using external XML
Forbid any network to the XML engine, by configuring the XML engine without network access
1.2.986.2. Specs¶
Short name |
Security/NoNetForXmlLoad |
Rulesets |
|
Exakat since |
1.0.11 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.987. Avoid sleep()/usleep()¶
Pausing the script for a specific amount of time means that the Web server is also making all related resources sleep, such as database, sockets, session, etc. This may used to set up a DOS on the server.
<?php
$begin = microtime(true);
checkLogin($user, $password);
$end = microtime(true);
// Making all login checks looks the same
usleep(1000000 - ($end - $begin) * 1000000);
// Any hit on this page now uses 1 second, no matter if load is high or not
// Is it now possible to saturate the webserver in 1 s ?
?>
As much as possible, avoid delaying the end of the script.
sleep() and usleep() have less impact in commandline (CLI).
1.2.987.1. Suggestions¶
Add a deadline of usage in the session, and wait past this deadline to start serving again. Until then, abort immediately.
Use element in the GUI to delay or slow usage.
1.2.987.2. Specs¶
Short name |
Security/NoSleep |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.988. No Weak SSL Crypto¶
When enabling PHP’s stream SSL, it is important to use a safe protocol.
All the SSL protocols (1.0, 2.0, 3.0), and TLS (1.0 are unsafe. The best is to use the most recent TLS, version 1.2.
stream_socket_enable_crypto() and curl_setopt() are checked.
<?php
// This socket will use SSL v2, which
$socket = 'sslv2://www.example.com';
$fp = fsockopen($socket, 80, $errno, $errstr, 30);
?>
Using the TLS transport protocol of PHP will choose the version by itself.
See also Insecure Transportation Security Protocol Supported (TLS 1.0), The 2018 Guide to Building Secure PHP Software and Internet Domain: TCP, UDP, SSL, and TLS.
1.2.988.1. Suggestions¶
Use TLS transport, with version 1.2
1.2.988.2. Specs¶
Short name |
Security/NoWeakSSLCrypto |
Rulesets |
|
Exakat since |
1.9.6 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.989. Register Globals¶
register_globalswas a PHP directive that dumped all incoming variables from GET, POST, COOKIE and FILES as global variables in the called scripts.
This lead to security failures, as the variables were often used but not filtered.
Though it is less often found in more recent code, register_globals is sometimes needed in legacy code, that haven’t made the move to eradicate this style of coding.
Backward compatible pieces of code that mimic the register_globals features usually create even greater security risks by being run after scripts startup. At that point, some important variables are already set, and may be overwritten by the incoming call, creating confusion in the script.
Mimicking register_globals is achieved with variables variables, extract(), parse_str() and import_request_variables() (Up to PHP 5.4).
<?php
// Security warning ! This overwrites existing variables.
extract($_POST);
// Security warning ! This overwrites existing variables.
foreach($_REQUEST as $var => $value) {
$$var = $value;
}
?>
1.2.989.1. Suggestions¶
Avoid reimplementing register_globals
Use a container to store and access commonly used values
1.2.989.2. Specs¶
Short name |
Security/RegisterGlobals |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Critical |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Examples |
|
Available in |
1.2.990. Safe HTTP Headers¶
Avoid configuring HTTP headers with lax restriction from within PHP.
There are a lot of HTTP headers those days, targeting various vulnerabilities. To ensure backward compatibility, those headers have a default mode that is lax and permissive. It is recommended to avoid using those from within the code.
<?php
//Good configuration, limiting access to origin
header('Access-Control-Allow-Origin: https://www.exakat.io');
//Configuration is present, but doesn't restrict anything : any external site is a potential source
header('Access-Control-Allow-Origin: *');
?>
See also Hardening Your HTTP Security Headers, How To Secure Your Web App With HTTP Headers and SecurityHeaders.
1.2.990.1. Suggestions¶
Remove usage of those headers
1.2.990.2. Specs¶
Short name |
Security/SafeHttpHeaders |
Rulesets |
|
Exakat since |
1.5.5 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.991. Sensitive Argument¶
Spot the argument that are sensitive for security. The functioncalls that are hosting a sensitive argument are called a sink.
<?php
// first argument $query is a sensitive argument
mysqli_query($query);
?>
1.2.991.1. Specs¶
Short name |
Security/SensitiveArgument |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.992. Session Lazy Write¶
Classes that implements SessionHandlerInterface must also implements SessionUpdateTimestampHandlerInterface.
The two extra methods are used to help lazy loading : the first actually checks if a sessionId is available, and the seconds updates the time of last usage of the session data in the session storage.
This was spotted by Nicolas Grekas, and fixed in Symfony [HttpFoundation] Make sessions secure and lazy #24523.
<?php
interface SessionUpdateTimestampHandlerInterface {
// returns a boolean to indicate that valid data is available for this sessionId, or not.
function validateId($sessionId);
//called to change the last time of usage for the session data.
//It may be a file's touch or full write, or a simple update on the database
function updateTimestamp($sessionId, $sessionData);
}
?>
See also Sessions: Improve original RFC about lazy_write and the Sessions.
1.2.992.1. Suggestions¶
Implements the SessionUpdateTimestampHandlerInterface interface
1.2.992.2. Specs¶
Short name |
Security/SessionLazyWrite |
Rulesets |
|
Exakat since |
0.12.15 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.993. Set Cookie Safe Arguments¶
The last five arguments of setcookie() and setrawcookie() are for security. Use them anytime you can.
setcookie ( string $name [, string $value = [, int $expire = 0 [, string $path = [, string $domain = [, bool $secure = false [, bool $httponly = false ]]]]]] )
The $expire argument sets the date of expiration of the cookie. It is recommended to make it as low as possible, to reduce its chances to be captured. Sometimes, low expiration date may be several days (for preferences), and other times, low expiration date means a few minutes.
The $path argument limits the transmission of the cookie to URL whose path matches the one mentioned here. By default, it is '/', which means the whole server. If a cookie usage is limited to a part of the application, use it here.
The $domain argument limits the transmission of the cookie to URL whose domain matches the one mentioned here. By default, it is '', which means any server on the internet. At worse, you may use mydomain.com to cover your whole domain, or better, refine it with the actual subdomain of usage.
The $secure argument limits the transmission of the cookie over HTTP (by default) or HTTPS. The second is better, as the transmission of the cookie is crypted. In case HTTPS is still at the planned stage, use ‘$_SERVER[HTTPS]’. This environment variable is false on HTTP, and true on HTTPS.
The $httponly argument limits the access of the cookie to JavaScript. It is only transmitted to the browser, and retransmitted. This helps reducing XSS and CSRF attacks, though it is disputed.
The $samesite argument limits the sending of the cookie to the domain that initiated the request. It is by default Lax but should be upgraded to Strict whenever possible. This feature is available as PHP 7.3.
<?php
//admin cookie, available only on https://admin.my-domain.com/system/, for the next minute, and not readable by javascript
setcookie(admin, $login, time()+60, /system/, admin.my-domain.com, $_SERVER['HTTPS'], 1);
//login cookie, available until the browser is closed, over http or https
setcookie(login, $login);
//removing the login cookie : Those situations are omitted by the analysis
setcookie(login, '');
?>
See also setcookie and ‘SameSite’ cookie attribute.
1.2.993.1. Suggestions¶
Use all the argument when setting cookies with PHP functions
1.2.993.2. Specs¶
Short name |
Security/SetCookieArgs |
Rulesets |
|
Exakat since |
0.10.6 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.994. Should Use Prepared Statement¶
Modern databases provides support for prepared statement : it separates the query from the processed data and raise significantly the security.
Building queries with concatenations is not recommended, though not always avoidable. When possible, use prepared statements.
<?php
/* Execute a prepared statement by passing an array of values */
$sql = 'SELECT name, colour, calories
FROM fruit
WHERE calories < :calories AND colour = :colour';
$sth = $conn->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
$sth->execute(array(':calories' => 150, ':colour' => 'red'));
$red = $sth->fetchAll();
?>
Same code, without preparation :
<?php
$sql = 'SELECT name, color, calories FROM fruit WHERE calories < '.$conn-quote(150).' AND colour = '.$conn->quotes('red').' ORDER BY name';
$sth = $conn->query($sql) as $row);
}
?>
- See also Prepared Statements <https://www.php.net/manual/en/`mysqli.quickstart.prepared-statements.php>`_,
PHP `MySQLi Prepared Statements Tutorial to Prevent SQL Injection <https://websitebeaver.com/prepared-statements-in-php-mysqli-to-prevent-sql-injection>`_, The Best Way to Perform `MYSQLI Prepared Statements in PHP <https://developer.hyvor.com/php/prepared-statements>`_.
1.2.994.1. Suggestions¶
Use an ORM
Use an Active Record library
Change the query to hard code it and make it not injectable
Name |
Default |
Type |
Description |
queryMethod |
query_methods.json |
data |
Methods that call a query. |
1.2.994.2. Specs¶
Short name |
Security/ShouldUsePreparedStatement |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Examples |
|
Available in |
1.2.995. Should Use session_regenerateid()¶
session_regenerateid() should be used when sessions are used.
When using sessions, a session ID is assigned to the user. It is a random number, used to connect the user and its data on the server. Actually, anyone with the session ID may have access to the data. This is why those session ID are so long and complex.
A good approach to protect the session ID is to reduce its lifespan : the shorter the time of use, the better. While changing the session ID at every hit on the page may no be possible, a more reasonable approach is to change the session id when an important action is about to take place. What important means is left to the application to decide.
Based on this philosophy, a code source that uses ZendSession but never uses ZendSession::regenerateId() has to be updated.
<?php
session_start();
$id = (int) $_SESSION['id'];
// no usage of session_regenerateid() anywhere triggers the analysis
// basic regeneration every 20 hits on the page.
if (++$_SESSION['count'] > 20) {
session_regenerateid();
}
?>
See session_regenerateid() and PHP Security Guide: Sessions.
1.2.995.1. Suggestions¶
Add session_regenerateid() call before any important operation on the application
1.2.995.2. Specs¶
Short name |
Security/ShouldUseSessionRegenerateId |
Rulesets |
|
Exakat since |
0.10.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.996. Sqlite3 Requires Single Quotes¶
The escapeString() method from
SQLite3doesn’t escape", but only'.
<?php
// OK. escapeString is OK with '
$query = "SELECT * FROM table WHERE col = '".$sqlite->escapeString($x)."'";
// This is vulnerable to " in $x
$query = 'SELECT * FROM table WHERE col = "'.$sqlite->escapeString($x).'"';
?>
To properly handle quotes and NUL characters, use bindParam() instead.
Quote from the PHP manual comments : The reason this function doesn't escape double quotes is because double quotes are used with names (the equivalent of backticks in MySQL), as in table or column names, while single quotes are used for values.
See also SQLite3::escapeString.
1.2.996.1. Suggestions¶
Use prepared statements whenever possible
Switch the query to use single quote
1.2.996.2. Specs¶
Short name |
Security/Sqlite3RequiresSingleQuotes |
Rulesets |
|
Exakat since |
1.0.10 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.997. Super Globals Contagion¶
Basic tainting system.
1.2.997.1. Specs¶
Short name |
Security/SuperGlobalContagion |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.998. Unserialize Second Arg¶
Since PHP 7, unserialize() function has a second argument that limits the classes that may be unserialized. In case of a breach, this is limiting the classes accessible from unserialize().
One way to exploit unserialize, is to make PHP unserialized the data to an available class, may be one that may be auto-loaded.
<?php
// safe unserialization : only the expected class will be extracted
$serialized = 'O:7:dbClass:0:{}';
$var = unserialize($serialized, ['dbClass']);
$var->connect();
// unsafe unserialization : $var may be of any type that was in the serialized string
// although, here, this is working well.
$serialized = 'O:7:dbClass:0:{}';
$var = unserialize($serialized);
$var->connect();
// unsafe unserialization : $var is not of the expected type.
// and, here, this will lead to disaster.
$serialized = 'O:10:debugClass:0:{}';
$var = unserialize($serialized);
$var->connect();
?>
See also unserialize(), Securely Implementing (De)Serialization in PHP, and Remote code execution via PHP [Unserialize].
1.2.998.1. Suggestions¶
Add a list of class as second argument of any call to unserialize(). This is valid for PHP 7.0 and later.
1.2.998.2. Specs¶
Short name |
Security/UnserializeSecondArg |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
7.0+ |
Severity |
Critical |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.999. Upload Filename Injection¶
When receiving a file via Upload, it is recommended to store it under a self-generated name. Any storage that uses the original filename, or even a part of it may be vulnerable to injections.
<?php
// Security error ! the $_FILES['upload']['filename'] is provided by the sender.
// 'a.<script>alert(\'a\')</script>'; may lead to a HTML injection.
$extension = substr( strrchr($_FILES['upload']['name'], '.') ,1);
if (!in_array($extension, array('gif', 'jpeg', 'jpg')) {
// process error
continue;
}
// Md5 provides a name without special characters
$name = md5($_FILES['upload']['filename']);
if(@move_uploaded_file($_FILES['upload']['tmp_name'], '/var/no-www/upload/'.$name.'.'.$extension)) {
safeStoring($name.'.'.$extension, $_FILES['upload']['filename']);
}
// Security error ! the $_FILES['upload']['filename'] is provided by the sender.
if(@move_uploaded_file($_FILES['upload']['tmp_name'], $_FILES['upload']['filename'])) {
safeStoring($_FILES['upload']['filename']);
}
// Security error ! the $_FILES['upload']['filename'] is provided by the sender.
// 'a.<script>alert('a')</script>'; may lead to a HTML injection.
$extension = substr( strrchr($_FILES['upload']['name'], '.') ,1);
$name = md5($_FILES['upload']['filename']);
if(@move_uploaded_file($_FILES['upload']['tmp_name'], $name.'.'.$extension)) {
safeStoring($name.'.'.$extension, $_FILES['upload']['filename']);
}
?>
It is highly recommended to validate any incoming file, generate a name for it, and store the result in a folder outside the web folder. Also, avoid accepting PHP scripts, if possible.
See also [CVE-2017-6090], CWE-616: Incomplete Identification of Uploaded File Variables, Why File Upload Forms are a Major Security Threat.
1.2.999.1. Suggestions¶
Validate uploaded filenames
Rename files upon storage, and keep the original name in a database
1.2.999.2. Specs¶
Short name |
Security/UploadFilenameInjection |
Rulesets |
|
Exakat since |
0.12.14 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.1000. parse_str() Warning¶
The parse_str() function parses a query string and assigns the resulting variables to the local scope. This may create a unexpected number of variables, and even overwrite the existing one.
<?php
function foo( ) {
global $a;
echo $a;
}
parse_str('a=1'); // No second parameter
foo( );
// displays 1
?>
Always use an empty variable a second parameter to parse_str(), so as to collect the incoming values, and then, filter them in that array.
1.2.1000.1. Suggestions¶
Use the second parameter when calling parse_url();
Change to PHP 8.0 version, which made the second argument compulsory
See also parse_url() and PHP SSRF Techniques.
1.2.1000.2. Specs¶
Short name |
Security/parseUrlWithoutParameters |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
With PHP 8.0 and older |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
Very high |
ClearPHP |
|
Available in |
1.2.1001. Adding Zero¶
Adding 0 is useless, as 0 is the neutral element for addition. Besides, when one of the argument is an integer, PHP triggers a cast to integer.
It is recommended to make the cast explicit with (int).
<?php
// Explicit cast
$a = (int) foo();
// Useless addition
$a = foo() + 0;
$a = 0 + foo();
// Also works with minus
$b = 0 - $c; // drop the 0, but keep the minus
$b = $c - 0; // drop the 0 and the minus
$a += 0;
$a -= 0;
?>
Adding zero is also reported when the zero is a defined constants.
If it is used to type cast a value to integer, then casting with (int) is clearer.
1.2.1001.1. Suggestions¶
Remove the +/- 0, may be the whole assignation
Use an explicit type casting operator (int)
1.2.1001.2. Specs¶
Short name |
Structures/AddZero |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
ClearPHP |
|
Examples |
|
Available in |
1.2.1002. Altering Foreach Without Reference¶
Foreach() loop that could use a reference as value.
When using a foreach loop that modifies the original source, it is recommended to use referenced variables, rather than access the original value with $source[$index].
Using references is then must faster, and easier to read.
<?php
// Using references in foreach
foreach($source as $key => &$value) {
$value = newValue($value, $key);
}
// Avoid foreach : use array_map
$source = array_walk($source, 'newValue');
// Here, $key MUST be the second argument or newValue
// Slow version to update the array
foreach($source as $key => &$value) {
$source[$key] = newValue($value, $key);
}
?>
array_walk() and array_map() are also alternative to prevent the use of foreach(), when $key is not used.
See also foreach.
1.2.1002.1. Suggestions¶
Add the reference on the modified blind variable, and avoid accessing the source array
1.2.1002.2. Specs¶
Short name |
Structures/AlteringForeachWithoutReference |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
ClearPHP |
|
Examples |
|
Available in |
1.2.1003. Alternative Syntax Consistence¶
PHP allows for two syntax : the alternative syntax, and the classic syntax.
The classic syntax is almost always used. When used, the alternative syntax is used in templates.
This analysis reports files that are using both syntax at the same time. This is confusing.
<?php
// Mixing both syntax is confusing.
foreach($array as $item) :
if ($item > 1) {
print $item elements\n;
} else {
print $item element\n;
}
endforeach;
?>
1.2.1003.1. Specs¶
Short name |
Structures/AlternativeConsistenceByFile |
Rulesets |
|
Exakat since |
0.11.2 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1004. Comparison Is Always True¶
Based on the incoming type of arguments, the comparison always yield the same value.
<?php
function foo(array $a) {
// This will always fail
if ($a === 1) {
} elseif (is_int($a)) {
}
// This will always succeed
if ($a !== null) {
} elseif (is_null($a)) {
}
}
?>
1.2.1004.1. Suggestions¶
Remove the constant condition and its corresponding blocks
Make the constant condition variable
1.2.1004.2. Specs¶
Short name |
Structures/AlwaysFalse |
Rulesets |
|
Exakat since |
1.9.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1005. Array_Fill() With Objects¶
array_fill() fills an array with identical objects, not copies nor clones. This means that all the filled objects are a reference to the same object. Changing one of them will change any of them.
Make sure this is the intended effect in the code.
<?php
$x = new StdClass();
$array = array_fill(0, 10, $x);
$array[3]->y = Set in object #3;
// displays Set in object #3;
echo $array[5]->y;
?>
This applies to array_pad() too. It doesn’t apply to array_fill_keys(), as objects will be cast to a string before usage in this case.
1.2.1005.1. Suggestions¶
Use a loop to fill in the array with cloned() objects.
1.2.1005.2. Specs¶
Short name |
Structures/ArrayFillWithObjects |
Rulesets |
|
Exakat since |
2.1.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1006. Array_Map() Passes By Value¶
array_map() requires the callback to receive elements by value. Unlink array_walk(), which accepts by value or by reference, depending on the action taken.
PHP 8.0 and more recent emits a Warning
<?php
// Example, courtery of Juliette Reinders Folmer
function trimNewlines(&$line, $key) {
$line = str_replace(array(\n, \r), '', $line);
}
$original = [
text\n\n,
text\n\r
];
$array = $original;
array_walk($array, 'trimNewlines');
var_dump($array);
array_map('trimNewlines', $original, [0, 1]);
?>
See also array_map.
1.2.1006.1. Suggestions¶
Make the callback first argument a reference
1.2.1006.2. Specs¶
Short name |
Structures/ArrayMapPassesByValue |
Rulesets |
|
Exakat since |
2.2.0 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
Medium |
Available in |
1.2.1007. array_merge() And Variadic¶
Always check value in variadic before using it with array_merge() and array_merge_recursive().
Before PHP 7.4, array_merge() and array_merge_recursive() would complain when no argument was provided. As such, using the spread operator … on an empty array() would yield no argument, and an error.
<?php
$b = array_merge(...$x);
?>
1.2.1007.1. Suggestions¶
Add a check to the spread variable to ensure it is not empty
Append an empty array to to the spread variable to ensure it is not empty
1.2.1007.2. Specs¶
Short name |
Structures/ArrayMergeAndVariadic |
Rulesets |
|
Exakat since |
1.9.2 |
PHP Version |
7.4- |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Available in |
1.2.1008. Array_merge Needs Array Of Arrays¶
When collecting data to feed array_merge(), use an array of array as default value.
`array(`array()) <https://www.php.net/array>`_`is the neutral value for array_merge();
This analysis also reports when the used types are not an array : array_merge() does not accept scalar values, but only arrays.
<?php
// safe default value
$a = array(array());
// when $list is empty, it is
foreach($list as $l) {
$a[] = $l;
}
$b = array_merge($a);
?>
Since PHP 7.4, it is possible to call array_merge() without an argument : this means the default value may an empty array. This array shall not contain scalar values.
See also array_merge.
1.2.1008.1. Suggestions¶
Use
`array(array())`or`[[]]`as default value for array_merge()Remove any non-array value from the values in the default array
1.2.1008.2. Specs¶
Short name |
Structures/ArrayMergeArrayArray |
Rulesets |
|
Exakat since |
2.1.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1009. array_merge With Ellipsis¶
Ellipsis, or …, returns a null when the operand array is empty. This doesn’t suit array_merge().
It is recommended to use a coalesce operator, to handle graciously an empty array : use an empty array as default value.
This applies to the following PHP functions :
<?php
// Correct usage of array_merge and ellipsis
$a = [ [1,2], [3,4]];
$b = array_merge(...$a);
// Notee the nested array
$a = [ ];
$b = array_merge(...$a ?: [[]] );
// Yield an error because $a is empty
$a = [ ];
$b = array_merge(...$a);
?>
1.2.1009.1. Suggestions¶
Use one of the coalesce operator to default to an empty array, avoiding a runtime warning.
Check the content of the expanded array before using it
1.2.1009.2. Specs¶
Short name |
Structures/ArrayMergeWithEllipsis |
Rulesets |
none |
Exakat since |
1.7.6 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1010. Searching For Multiple Keys¶
array_search() and array_keys() find keys in an array. array_search() returns the first key that match a value, while array_keys() returns all the keys that match a value.
array_search() and array_keys() both accepts a final parameter to set a strict search or not.
<?php
$array = array(0,1,2,3,4,3);
// $id = 3
$id = array_search($array, 3);
// $ids = [3, 5];
$ids = array_keys($array, 3);
?>
1.2.1010.1. Suggestions¶
Use array_keys() to find multiple keys in an array
Use array_keys() to find a unique key in an array
1.2.1010.2. Specs¶
Short name |
Structures/ArraySearchMultipleKeys |
Rulesets |
|
Exakat since |
2.2.0 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Unknown |
Available in |
1.2.1011. Assign And Compare¶
Assignation has a lower precedence than comparison. As such, the assignation always happens after the comparison. This leads to the comparison being stored in the variable, and not the value being compared.
<?php
if ($id = strpos($string, $needle) !== false) {
// $id now contains a boolean (true or false), but not the position of the $needle.
}
// probably valid comparison, as $found will end up being a boolean
if ($found = strpos($string, $needle) === false) {
doSomething();
}
// always valid comparison, with parenthesis
if (($id = strpos($string, $needle)) !== false) {
// $id now contains a boolean (true or false), but not the position of the $needle.
}
// Being a lone instruction, this is always valid : there is no double usage with if condition
$isFound = strpos($string, $needle) !== false;
?>
See also Operator Precedence.
1.2.1011.1. Suggestions¶
Use parenthesis
Separate assignation and comparison
Drop assignation or comparison
1.2.1011.2. Specs¶
Short name |
Structures/AssigneAndCompare |
Rulesets |
|
Exakat since |
1.6.3 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1012. Assigned In One Branch¶
Report variables that are assigned in one branch, and not in the other.
<?php
if ($condition) {
// $assigned_in_this_branch is assigned in only one of the branches
$assigned_in_this_branch = 1;
$also_assigned = 1;
} else {
// $also_assigned is assigned in the two branches
$also_assigned = 1;
}
?>
1.2.1012.1. Specs¶
Short name |
Structures/AssignedInOneBranch |
Rulesets |
|
Exakat since |
1.0.5 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1013. Same Variable Foreach¶
A foreach which uses its own source as a blind variable is actually broken.
Actually, PHP makes a copy of the source before it starts the loop. As such, the same variable may be used for both source and blind value.
Of course, this is very confusing, to see the same variables used in very different ways.
The source will also be destroyed immediately after the blind variable has been turned into a reference.
<?php
$array = range(0, 10);
foreach($array as $array) {
print $array.PHP_EOL;
}
print_r($array); // display number from 0 to 10.
$array = range(0, 10);
foreach($array as &$array) {
print $array.PHP_EOL;
}
print_r($array); // display 10
?>
1.2.1013.1. Specs¶
Short name |
Structures/AutoUnsetForeach |
Rulesets |
|
Exakat since |
1.0.5 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1014. Bail Out Early¶
When using conditions, it is recommended to quit in the current context, and avoid else clause altogether.
The main benefit is to make clear the method applies a condition, and stop immediately when it is not satisfied. The main sequence is then focused on the actual code.
This works with the break, continue, throw and goto keywords too, depending on situations.
<?php
// Bailing out early, low level of indentation
function foo1($a) {
if ($a > 0) {
return false;
}
$a++;
return $a;
}
// Works with continue too
foreach($array as $a => $b) {
if ($a > 0) {
continue false;
}
$a++;
return $a;
}
// No need for else
function foo2($a) {
if ($a > 0) {
return false;
} else {
$a++;
}
return $a;
}
// No need for else : return goes into then.
function foo3($a) {
if ($a < 0) {
$a++;
} else {
return false;
}
return $a;
}
// Make a return early, and make the condition visible.
function foo3($a) {
if ($a < 0) {
$a++;
methodcall();
functioncall();
}
}
?>
See also Avoid nesting too deeply and return early (part 1) and Avoid nesting too deeply and return early (part 2).
1.2.1014.1. Suggestions¶
Detect errors, and then, return as soon as possible.
When a if…then branches are unbalanced, test for the small branch, finish it with return. Then keep the other branch as the main code.
1.2.1014.2. Specs¶
Short name |
Structures/BailOutEarly |
Rulesets |
|
Exakat since |
0.8.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1015. Use Basename Suffix¶
basename() will remove extension when it is provided as argument. The second argument will be removed from the name of the file.
<?php
$path = 'phar:///path/to/file.php';
// Don't forget the .
$filename = basename($path, '.php');
// Too much work for this
$filename = substr(basename($path), 0, -4);
?>
Using basename() instead of substr() or else, makes the intention clear.
See also basename.
1.2.1015.1. Suggestions¶
Use basename(), remove more complex code based on substr() or str_replace()
1.2.1015.2. Specs¶
Short name |
Structures/BasenameSuffix |
Rulesets |
|
Exakat since |
1.5.1 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Examples |
|
Available in |
1.2.1016. Strict Comparison With Booleans¶
Strict comparisons prevent from mistaking an error with a false.
Boolean values may be easily mistaken with other values, especially when the function may return integer or boolean as a normal course of action.
It is encouraged to use strict comparison === or !== when booleans are involved in a comparison.
<?php
// distinguish between : $b isn't in $a, and, $b is at the beginning of $a
if (strpos($a, $b) === 0) {
doSomething();
}
// DOES NOT distinguish between : $b isn't in $a, and, $b is at the beginning of $a
if (strpos($a, $b)) {
doSomething();
}
// will NOT mistake 1 and true
$a = array(0, 1, 2, true);
if (in_array($a, true, true)) {
doSomething();
}
// will mistake 1 and true
$a = array(0, 1, 2, true);
if (in_array($a, true)) {
doSomething();
}
?>
switch() structures always uses == comparisons.
Native function in_array() has a third parameter to make it use strict comparisons.
1.2.1016.1. Suggestions¶
Use strict comparison whenever possible
1.2.1017. Bracketless Blocks¶
It is generally considered a bad practice, as readability is lower and there are non-negligible risk of excluding from the loop the next instruction.
<?php
// Legit one liner
foreach(range('a', 'z') as $letter) ++$letterCount;
// More readable version, even for a one liner.
foreach(range('a', 'z') as $letter) {
++$letterCount;
}
?>
switch() cannot be without bracket.
1.2.1017.1. Specs¶
Short name |
Structures/Bracketless |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.1018. Break With 0¶
<?php
// Can't break 0. Must be 1 or more, depending on the level of nesting.
for($i = 0; $i < 10; $i++) {
break 0;
}
for($i = 0; $i < 10; $i++) {
for($j = 0; $j < 10; $j++) {
break 2;
}
}
?>
1.2.1018.1. Suggestions¶
Remove 0, or the break
1.2.1018.2. Specs¶
Short name |
Structures/Break0 |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
5.4- |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1019. Break With Non Integer¶
When using a break, the argument of the operator must be a positive non-null integer literal or be omitted.
Other values were acceptable in PHP 5.3 and previous version, but this is now reported as an error.
<?php
// Can't break $a, even if it contains an integer.
$a = 1;
for($i = 0; $i < 10; $i++) {
break $a;
}
// can't break on float
for($i = 0; $i < 10; $i++) {
for($j = 0; $j < 10; $j++) {
break 2.2;
}
}
?>
1.2.1019.1. Specs¶
Short name |
Structures/BreakNonInteger |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
5.4- |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1020. Break Outside Loop¶
It is not possible anymore to include a piece of code inside a loop that will then break.
<?php
// outside a loop : This won't compile
break 1;
foreach($array as $a) {
break 1; // Compile OK
break 2; // This won't compile, as this break is in one loop, and not 2
}
foreach($array as $a) {
foreach($array2 as $a2) {
break 2; // OK in PHP 5 and 7
}
}
?>
1.2.1020.1. Specs¶
Short name |
Structures/BreakOutsideLoop |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
7.0- |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1021. Buried Assignation¶
Those assignations are buried in the code, and placed in unexpected situations.
They are difficult to spot, and may be confusing. It is advised to place them in a more visible place.
<?php
// $b may be assigned before processing $a
$a = $c && ($b = 2);
// Display property p immeiately, but also, keeps the object for later
echo ($o = new x)->p;
// legit syntax, but the double assignation is not obvious.
for($i = 2, $j = 3; $j < 10; $j++) {
}
?>
1.2.1021.1. Suggestions¶
Extract the assignation and set it on its own line, prior to the current expression.
Check if the local variable is necessary
1.2.1021.2. Specs¶
Short name |
Structures/BuriedAssignation |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Examples |
|
Available in |
1.2.1022. Calltime Pass By Reference¶
PHP doesn’t allow when a value is turned into a reference at functioncall, since PHP 5.4.
Either the function use a reference in its signature, either the reference won’t pass.
<?php
function foo($name) {
$arg = ucfirst(strtolower($name));
echo 'Hello '.$arg;
}
$a = 'name';
foo(&$a);
?>
1.2.1022.1. Suggestions¶
Make the signature of the called method accept references
Remove the reference from the method call
Use an object instead of a scalar
See also and Passing by Reference.
1.2.1022.2. Specs¶
Short name |
Structures/CalltimePassByReference |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
With PHP 5.4 and older |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1023. Can’t Count Non-Countable¶
<?php
// Normal usage
$a = array(1,2,3,4);
echo count($a).items\n;
// Error emiting usage
$a = '1234';
echo count($a).chars\n;
// Error emiting usage
echo count($unsetVar).elements\n;
?>
See also Warn when counting non-countable types.
1.2.1023.1. Suggestions¶
Add a check before using count such as a type check
1.2.1023.2. Specs¶
Short name |
Structures/CanCountNonCountable |
Rulesets |
|
Exakat since |
1.0.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
Medium |
Available in |
1.2.1024. Cast To Boolean¶
This expression may be reduced by casting to boolean type.
<?php
$variable = $condition == 'met' ? 1 : 0;
// Same as
$variable = (bool) $condition == 'met';
$variable = $condition == 'met' ? 0 : 1;
// Same as (Note the condition inversion)
$variable = (bool) $condition != 'met';
// also, with an indentical condition
$variable = !(bool) $condition == 'met';
// This also works with straight booleans expressions
$variable = $condition == 'met' ? true : false;
// Same as
$variable = $condition == 'met';
?>
1.2.1024.1. Suggestions¶
Remove the old expression and use
(bool)operator insteadChange the target values from true/false, or 0/1 to non-binary values, like strings or integers beyond 0 and 1.
Complete the current branches with other commands
See also and .
1.2.1024.2. Specs¶
Short name |
Structures/CastToBoolean |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
Very high |
Examples |
|
Available in |
1.2.1025. Casting Ternary¶
Type casting has a precedence over ternary operator, and is applied first. When this happens, the condition is cast, although it is often useless as PHP will do it if needed.
This applies to the ternary operator, the coalesce operator ?: and the null-coalesce operator ??.
<?php
$a = (string) $b ? 3 : 4;
$a = (string) $b ?: 4;
$a = (string) $b ?? 4;
?>
The last example generates first an error Undefined variable: b, since $b is first cast to a string. The result is then an empty string, which leads to an empty string to be stored into $a. Multiple errors cascade.
See also Operators Precedence.
1.2.1025.1. Suggestions¶
Add parenthesis around the ternary operator
Skip the casting
Cast in another expression
1.2.1025.2. Specs¶
Short name |
Structures/CastingTernary |
Rulesets |
|
Exakat since |
1.8.0 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1026. Catch Overwrite Variable¶
The try/catch structure uses some variables that are also in use in this scope. In case of a caught exception, the exception will be put in the catch variable, and overwrite the current value, loosing some data.
<?php
// variables and caught exceptions are distinct
$argument = 1;
try {
methodThatMayRaiseException($argument);
} (Exception $e) {
// here, $e has been changed to an exception.
}
// variables and caught exceptions are overlapping
$e = 1;
try {
methodThatMayRaiseException();
} (Exception $e) {
// here, $e has been changed to an exception.
}
?>
It is recommended to use another name for these catch variables.
1.2.1026.1. Suggestions¶
Use a standard : only use $e (or else) to catch exceptions. Avoid using them for anything else, parameter, property or local variable.
Change the variable, and keep the caught exception
1.2.1026.2. Specs¶
Short name |
Structures/CatchShadowsVariable |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
ClearPHP |
|
Examples |
|
Available in |
1.2.1027. Check All Types¶
When checking for time, avoid using else. Mention explicitly all tested type, and raise an exception when reaching else.
PHP has a short list of scalar types : null, boolean, integer, real, strings, object, resource and array. When a variable is not holding one the the type, then it may be of any other type.
Most of the time, when using a simple is_string() / else test, this is relying on the conception of the code. By construction, the arguments may be one of two types : array or string.
What happens often is that in case of failure in the code (database not working, another class not checking its results), a third type is pushed to the structure, and it ends up breaking the execution.
The safe way is to check the various types all the time, and use the default case (here, the else) to throw exception() or test an assertion and handle the special case.
<?php
// hasty version
if (is_array($argument)) {
$out = $argument;
} else {
// Here, $argument is NOT an array. What if it is an object ? or a NULL ?
$out = array($argument);
}
// Safe type checking : do not assume that 'not an array' means that it is the other expected type.
if (is_array($argument)) {
$out = $argument;
} elseif (is_string($argument)) {
$out = array($argument);
} else {
assert(false, '$argument is not an array nor a string, as expected!');
}
?>
Using is_callable(), is_iterable() with this structure is fine : when variable is callable or not, while a variable is an integer or else.
Using a type test without else is also accepted here. This is a special treatment for this test, and all others are ignored. This aspect may vary depending on situations and projects.
1.2.1027.1. Suggestions¶
Include a default case to handle all unknown situations
Include and process explicit types as much as possible
1.2.1027.2. Specs¶
Short name |
Structures/CheckAllTypes |
Rulesets |
|
Exakat since |
0.10.6 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1028. Check JSON¶
Check errors whenever JSON is encoded or decoded.
In particular, NULL is a valid decoded JSON response. If you want to avoid mistaking NULL for an error, it is recommended to call json_last_error.
<?php
$encoded = json_encode($incoming);
// Unless JSON must contains some non-null data, this mistakes NULL and error
if(json_last_error() != JSON_ERROR_NONE) {
die('Error when encoding JSON');
}
$decoded = json_decode($incoming);
// Unless JSON must contains some non-null data, this mistakes NULL and error
if($decoded === null) {
die('ERROR');
}
?>
See also Option to make json_encode and json_decode throw exceptions on errors, json_last_error.
1.2.1028.1. Suggestions¶
Always check after JSON operation : encoding or decoding.
Add a call to json_last_error()
Configure operations to throw an exception upon error (
JSON_THROW_ON_ERROR), and catch it.
1.2.1028.2. Specs¶
Short name |
Structures/CheckJson |
Rulesets |
|
Exakat since |
1.3.0 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1029. Coalesce And Concat¶
The concatenation operator dot has precedence over the coalesce operator ??.
<?php
// Parenthesis are the right solution when in doubt
echo a . ($b ?? 'd') . $e;
// 'a' . $b is evaluated first, leading ot a useless ?? operator
'a' . $b ?? $c;
// 'd' . 'e' is evaluated first, leading to $b OR 'de'.
echo $b ?? 'd' . 'e';
?>
1.2.1029.1. Suggestions¶
Add parenthesis around ?? operator to avoid misbehavior
Do not use dot and ?? together in the same expression
1.2.1029.2. Specs¶
Short name |
Structures/CoalesceAndConcat |
Rulesets |
|
Exakat since |
1.9.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1030. Common Alternatives¶
In the following conditional structures, expressions were found that are common to both ‘then’ and ‘else’. It may be interesting, though not always possible, to put them both out of the conditional, and reduce line count.
<?php
if ($c == 5) {
$b = strtolower($b[2]);
$a++;
} else {
$b = strtolower($b[2]);
$b++;
}
?>
may be rewritten in :
<?php
$b = strtolower($b[2]);
if ($c == 5) {
$a++;
} else {
$b++;
}
?>
1.2.1030.1. Suggestions¶
Collect common expressions, and move them before of after the if/then expression.
Move a prefix and suffixes to a third-party method
1.2.1030.2. Specs¶
Short name |
Structures/CommonAlternatives |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1031. Compared But Not Assigned Strings¶
Those strings are compared to variables in the code, but those values are never assigned.
<?php
$a = 'b';
// Depending on the origin of $b, is this possible?
if ($b === 'c') {
}
?>
1.2.1031.1. Specs¶
Short name |
Structures/ComparedButNotAssignedStrings |
Rulesets |
|
Exakat since |
1.3.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1032. Compared Comparison¶
Usually, comparison are sufficient, and it is rare to have to compare the result of comparison. Check if this two-stage comparison is really needed.
<?php
if ($a === strpos($string, $needle) > 2) {}
// the expression above apply precedence :
// it is equivalent to :
if (($a === strpos($string, $needle)) > 2) {}
?>
See also Operators Precedence.
1.2.1032.1. Specs¶
Short name |
Structures/ComparedComparison |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1033. Strict Or Relaxed Comparison¶
PHP has two comparison styles : strict and relaxed.
The analyzed code has less than 10% of one of them : for consistency reasons, it is recommended to make them all the same.
It is recommended to always use the strict comparison by default, and use the relaxed in case of specific situations.
<?php
// This compares $strict both in terms of value and type
if ($strict === 3) {
} elseif ($strict == 3) {
// This compares $strict after an possible type casting.
// '3', 3.0 or 3 would all be possible solutions.
}
?>
See also and Comparison Operators.
1.2.1033.1. Specs¶
Short name |
Structures/ComparisonFavorite |
Rulesets |
|
Exakat since |
1.3.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1034. Too Complex Expression¶
Long expressions should be broken in small chunks, to limit complexity.
Really long expressions tends to be error prone : either by typo, or by missing details. They are even harder to review, once the initially build of the expression is gone.
As a general rule, it is recommended to keep expressions short. The analysis include any expression that is more than 15 tokens large : variable and operators counts as one, properties, arrays count as two. Parenthesis are also counted.
PHP has no specific limit to expression size, so long expression are legal and valid. It is possible that the business logic requires a complex equation.
<?php
// Why not calculate wordwrap size separatedly ?
$a = explode("\n", wordwrap($this->message, floor($this->width / imagefontwidth($this->fontsize)), "\n"));
// Longer but easier to read
$width = floor($this->width / imagefontwidth($this->fontsize)), "\n");
$a = explode("\n", wordwrap($this->message, $width);
// Here, some string building, including error management with @, is making the data quite complex.
fwrite($fp, 'HEAD ' . @$url['path'] . @$url['query'] . ' HTTP/1.0' . "\r\n" . 'Host: ' . @$url['host'] . "\r\n\r\n")
// Better validation of data.
$http_header = 'HEAD ';
if (isset($url['path'])) {
$http_header .= $url['path'];
}
if (isset($url['query'])) {
$http_header .= $url['query'];
}
$http_header .= "\r\n";
if (isset($url['host'])) {
$http_header .= 'Host: ' . $url['host'] . "\r\n\r\n";
}
fwrite($fp, $http_header);
?>
1.2.1034.1. Suggestions¶
Reduce complexity by breaking the expressions into smaller ones
Name |
Default |
Type |
Description |
complexExpressionThreshold |
30 |
integer |
Minimal number of operators in one expression to report. |
1.2.1034.2. Specs¶
Short name |
Structures/ComplexExpression |
Rulesets |
|
Exakat since |
0.12.16 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1035. Concat Empty String¶
Using a concatenation to make a value a string should be replaced with a type cast.
Type cast to a string is done with (string) operator. There is also the function strval(), although it is less recommended.
<?php
$a = 3;
// explicite way to cast a value
$b = (string) $a; // $b is a string with the content 3
// Wrong way to cast a value
$c = $a . ''; // $c is a string with the content 3
$c = '' . $a; // $c is a string with the content 3
$a .= ''; // $a is a string with the content 3
// Wrong way to cast a value
$c = $a . '' . $b; // This is not reported. The empty string is useless, but not meant to type cast
?>
See also Type Casting and PHP Type Casting.
1.2.1035.1. Suggestions¶
Avoid concatenating with empty strings
Use (string) operator to cast to string
Remove any concatenated empty string
1.2.1035.2. Specs¶
Short name |
Structures/ConcatEmpty |
Rulesets |
|
Exakat since |
1.8.0 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1036. Concatenation Interpolation Consistence¶
Concatenations are done with the . operator or by interpolation inside a string.
Interpolation is a clean way to write concatenation, though it gets messy with long dereferences or with constants. Concatenations are longer to write.
The analyzed code has less than 10% of one of them : for consistency reasons, it is recommended to make them all the same.
<?php
// be consistent
$a = $b $c;
$d = $b $e;
$e = $b $e;
$d = $b $f;
$f = $b $z;
$h = $b $e;
$y = $b $e;
$d = $b $x;
$j = $b $c;
$d = $b $g;
$d = $b $h;
// Be consistent, always use the same.
$z = $w.' '.$e;
?>
1.2.1036.1. Specs¶
Short name |
Structures/ConcatenationInterpolationFavorite |
Rulesets |
|
Exakat since |
0.11.6 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1037. Conditional Structures¶
Structures that are defined, but only executed conditionally.
<?php
if (!function_exists('array_column')) {
function array_column($a) {
// some PHP
}
}
if (!class_exists('foo')) {
class foo {
}
}
?>
1.2.1037.1. Specs¶
Short name |
Structures/ConditionalStructures |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1038. Const Or Define¶
constanddefine()have the same functional use : create constants.
The analyzed code has less than 10% of one of them : for consistency reasons, it is recommended to make them all the same.
They are almost interchangeable, though not totally : define() allows the creation of case-insensitive constants, while Const won't.
<?php
// be consistent
const A1 = 1 ;
const A2 = 2 ;
const A3 = 3 ;
const A4 = 4 ;
const A5 = 5 ;
const A6 = 6 ;
const A7 = 7 ;
const A8 = 8 ;
const A9 = 9 ;
const A10 = 10;
const A11 = 11;
define('A12', 12); // Be consistent, always use the same.
?>
1.2.1038.1. Specs¶
Short name |
Structures/ConstDefineFavorite |
Rulesets |
|
Exakat since |
0.12.1 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1039. Constant Comparison¶
Constant to the left or right is a favorite.
Comparisons are commutative : they may be $a == B or B == $a. The analyzed code show less than 10% of one of the two : for consistency reasons, it is recommended to make them all the same.
Putting the constant on the left is also called ‘Yoda Comparison’, as it mimics the famous characters style of speech. It prevents errors like ‘B = $a’ where the comparison is turned into an assignation.
The natural way is to put the constant on the right. It is often less surprising.
Every comparison operator is used when finding the favorite.
<?php
//
if ($a === B) { doSomething(); }
if ($c > D) { doSomething(); }
if ($e !== G) { doSomething(); }
do { doSomething(); } while ($f === B);
while ($a === B) { doSomething(); }
// be consistent
if (B === $a) {}
// Compari
if (B <= $a) {}
?>
1.2.1039.1. Specs¶
Short name |
Structures/ConstantComparisonConsistance |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1040. Constant Conditions¶
If/then structures have constant condition.
The condition doesn’t change during execution, and the following blocks are always executed or not. This may also lead to an infinite or a null loop.
When this is the case, the condition may be removed, and dead code may be removed.
<?php
// static if
if (0.8) {
$a = $x;
} else {
$a = $y;
}
// static while
while (1) {
$a = $x;
}
// static do..while
do {
$a = $x;
} while ('b'. 'c');
// constant for() : No increment
for ($i = 0; $i < 10; ) {
$a = $x;
}
// constant for() : No final check
for ( $i = 0; ; ++$i) {
$a = $x;
}
// static ternary
$a = TRUE ? $x : $y;
?>
It is advised to remove them, or to make them depend on configuration.
1.2.1040.1. Specs¶
Short name |
Structures/ConstantConditions |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1041. Constant Scalar Expressions¶
Define constant with the result of static expressions. This means that constants may be defined with the const keyword, with the help of various operators but without any functioncalls.
This feature was introduced in PHP 5.6. It also supports array(), and expressions in arrays.
Those expressions (using simple operators) may only manipulate other constants, and all values must be known at compile time.
<?php
// simple definition
const A = 1;
// constant scalar expression
const B = A * 3;
// constant scalar expression
const C = [A ** 3, '3' => B];
?>
See also Constant Scalar Expressions.
1.2.1041.1. Specs¶
Short name |
Structures/ConstantScalarExpression |
Rulesets |
Appinfo, CE, CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, All |
Exakat since |
0.8.4 |
PHP Version |
5.6+ |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1042. Continue Is For Loop¶
Since PHP 7.3, the execution will emit a warning when finding a continue inside a switch inside a loop : ‘”continue” targeting switch is equivalent to “break”. Did you mean to use “continue 2”?’
<?php
while ($foo) {
switch ($bar) {
case 'baz':
continue; // In PHP: Behaves like 'break;'
// In C: Behaves like 'continue 2;'
}
}
?>
See also Deprecate and remove `continue targeting switch <https://wiki.php.net/rfc/continue_on_switch_deprecation>`_.
1.2.1042.1. Suggestions¶
Replace break by continue
1.2.1042.2. Specs¶
Short name |
Structures/ContinueIsForLoop |
Rulesets |
Analyze, CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, CompatibilityPHP70, CompatibilityPHP71, CompatibilityPHP72, CompatibilityPHP73, All |
Exakat since |
1.3.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1043. Could Be Else¶
Merge opposition conditions into one if/then structure.
When two if/then structures follow each other, using a condition and its opposite, they may be merged into one.
<?php
// Short version
if ($a == 1) {
$b = 2;
} else {
$b = 1;
}
// Long version
if ($a == 1) {
$b = 2;
}
if ($a != 1) {
$b = 3;
}
?>
1.2.1043.1. Suggestions¶
Merge the two conditions into one structure
Check if the second condition is still applicable
1.2.1043.2. Specs¶
Short name |
Structures/CouldBeElse |
Rulesets |
|
Exakat since |
1.0.1 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1044. Could Be Static¶
This global is only used in one function or method. It may be called ‘static’, instead of global. This allows you to keep the value between call to the function, but will not be accessible outside this function.
<?php
function foo( ) {
static $variableIsReservedForX; // only accessible within foo( ), even between calls.
global $variableIsGlobal; // accessible everywhere in the application
}
?>
1.2.1044.1. Specs¶
Short name |
Structures/CouldBeStatic |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1045. Could Use array_fill_keys¶
array_fill_keys() is a native PHP function that creates an array from keys. It gets the list of keys, and a constant value to assign to each keys.
This is twice faster than doing the same with a loop.
Note that is possible to use an object as initializing value : every element of the final array will be pointing to the same value. And, also, using an object as initializing value means that the same object will be used for each key : the object will not be cloned for each value.
<?php
$array = range('a', 'z');
// Fast way to build the array
$b = array_fill_keys($a, 0);
// Fast way to build the array, but every element will be the same object
$b = array_fill_keys($a, new Stdclass());
// Slow way to build the array
foreach($array as $a) {
$b[$a] = 0;
}
// Setting everything to null, slowly
$array = array_map(function() {}, $array);
?>
See also array_fill_keys.
1.2.1045.1. Suggestions¶
Use array_fill_keys()
1.2.1045.2. Specs¶
Short name |
Structures/CouldUseArrayFillKeys |
Rulesets |
|
Exakat since |
1.1.7 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Examples |
|
Available in |
1.2.1046. Could Use array_unique¶
Use array_unique() to collect unique elements from an array.
Always try to use native PHP functions, instead of rebuilding them with custom PHP code.
<?php
$unique = array();
foreach ($array as $b) {
if (!in_array($b, $unique)) {
/* May be more code */
$unique[] = $b;
}
}
?>
See also array_unique.
1.2.1046.1. Suggestions¶
Turn the foreach() and its condition into a call to array_unique()
Extract the condition from the foreach() and add a separate call to array_unique()
1.2.1046.2. Specs¶
Short name |
Structures/CouldUseArrayUnique |
Rulesets |
|
Exakat since |
1.2.6 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1047. Could Use Compact¶
Compact() turns a group of variables into an array. It may be used to simplify expressions.
<?php
$a = 1;
$b = 2;
// Compact call
$array = compact('a', 'b');
$array === [1, 2];
// Detailing all the keys and their value
$array = ['a' => $a, 'b' => $b];
?>
Note that compact accepts any string, and any undefined variable is not set, without a warning.
See also compact.
1.2.1047.1. Suggestions¶
Replace the array() call with a compact() call.
1.2.1047.2. Specs¶
Short name |
Structures/CouldUseCompact |
Rulesets |
|
Exakat since |
1.1.6 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1048. Could Use __DIR__¶
Avoid using dirname() on __FILE__.
<?php
// Better way
$fp = fopen(__DIR__.'/myfile.txt', 'r');
// compatible, but slow way
$fp = fopen(dirname(__FILE__).'/myfile.txt', 'r');
// Since PHP 5.3
assert(dirname(__FILE__) == __DIR__);
?>
__DIR__ has been introduced in PHP 5.3.0.
See also Magic Constants.
1.2.1048.1. Suggestions¶
Use __DIR__ instead of
dirname(__FILE__);
1.2.1048.2. Specs¶
Short name |
Structures/CouldUseDir |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1049. Could Use Match¶
The simplest case for such refactoring is when each of the switch’s case (including default), assign one value to the same variable. See this below :
<?php
switch($a) {
case 1:
$b = '1';
break;
case 2:
$b = '3';
break;
default:
$b = '0';
break;
}
/*
$b = match($a) {
1 => '1',
2 => '3',
default => '0'
};
*/
?>
Match() was introduced in PHP 8. It is not valid with older PHP versions.
See also Match().
1.2.1049.1. Suggestions¶
Replace switch() with match()
1.2.1049.2. Specs¶
Short name |
Structures/CouldUseMatch |
Rulesets |
|
Exakat since |
2.2.2 |
PHP Version |
8.0+ |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Unknown |
Available in |
1.2.1050. Could Use Short Assignation¶
Use short assignment operator, to speed up code, and keep syntax clear.
Some operators, like * or +, have a compact and fast ‘do-and-assign’ version. They looks like a compacted version for = and the operator. This syntax is good for readability, and saves some memory in the process.
Depending on the operator, not all permutations of arguments are possible.
Addition and short assignation of addition have a different set of features when applied to arrays. Do not exchange one another in that case.
<?php
$a = 10 + $a;
$a += 10;
$b = $b - 1;
$b -= 1;
$c = $c * 2;
$c *= 2;
$d = $d / 3;
$d /= 3;
$e = $e % 4;
$e %= 4;
$f = $f | 5;
$f |= 5;
$g = $g & 6;
$g &= 6;
$h = $h ^ 7;
$h ^= 7;
$i = $i >> 8;
$i >>= 8;
$j = $j << 9;
$j <<= 9;
// PHP 7.4 and more recent
$l = $l ?? 'value';
$l ??= 'value';
?>
Short operators are faster than the extended version, though it is a micro-optimization.
See also Assignation Operators.
1.2.1050.1. Suggestions¶
Change the expression to use the short assignation
1.2.1050.2. Specs¶
Short name |
Structures/CouldUseShortAssignation |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
ClearPHP |
|
Examples |
|
Available in |
1.2.1051. Could Use str_repeat()¶
Use str_repeat() or str_pad() instead of making a loop.
Making a loop to repeat the same concatenation is actually much longer than using str_repeat(). As soon as the loop repeats more than twice, str_repeat() is much faster. With arrays of 30, the difference is significant, though the whole operation is short by itself.
<?php
// This adds 7 'e' to $x
$x .= str_repeat('e', 7);
// This is the same as above,
for($a = 3; $a < 10; ++$a) {
$x .= 'e';
}
// here, $default must contains 7 elements to be equivalent to the previous code
foreach($default as $c) {
$x .= 'e';
}
?>
1.2.1051.1. Suggestions¶
Use strrepeat() whenever possible
1.2.1051.2. Specs¶
Short name |
Structures/CouldUseStrrepeat |
Rulesets |
|
Exakat since |
0.11.0 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
Very high |
Examples |
|
Available in |
1.2.1052. crypt() Without Salt¶
PHP requires a salt when calling crypt(). 5.5 and previous versions didn’t require it. Salt is a simple string, that is usually only known by the application.
According to the manual : The salt parameter is optional. However, crypt() creates a weak hash without the salt. PHP 5.6 or later raise an E_NOTICE error without it. Make sure to specify a strong enough salt for better security.
<?php
// Set the password
$password = 'mypassword';
// salted crypt usage (always valid)
$hash = crypt($password, '123salt');
// Get the hash, letting the salt be automatically generated
// This generates a notice after PHP 5.6
$hash = crypt($password);
?>
1.2.1052.2. Specs¶
Short name |
Structures/CryptWithoutSalt |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
5.6- |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.1053. curl_version() Has No Argument¶
curl_version() used to accept
CURLVERSION_NOWas argument. Since PHP 7.4, it is a function without arguments.
<?php
// Compatible syntax
$details = curl_version(CURLVERSION_NOW);
// New PHP 7.4 syntax
$details = curl_version();
?>
See also curl_version.
1.2.1053.1. Suggestions¶
Drop all arguments from curl_version() calls.
1.2.1053.2. Specs¶
Short name |
Structures/CurlVersionNow |
Rulesets |
|
Exakat since |
1.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1054. Dangling Array References¶
Always unset a referenced-variable used in a loop.
It is highly recommended to unset blind variables when they are set up as references after a loop.
<?php
$array = array(1,2,3,4);
foreach($array as &$a) {
$a += 1;
}
// This only unset the reference, not the value
unset($a);
// Dangling array problem
foreach($array as &$a) {
$a += 1;
}
//$array === array(3,4,5,6);
// This does nothing (apparently)
// $a is already a reference, even if it doesn't show here.
foreach($array as $a) {}
//$array === array(3,4,5,5);
?>
When omitting this step, the next loop that will also require this variable will deal with garbage values, and produce unexpected results.
See also : No Dangling Reference, PHP foreach pass-by-reference: Do it right, or better not at all, How does PHP ‘foreach’ actually work?, References and foreach.
1.2.1054.1. Suggestions¶
Avoid using the reference altogether : sometimes, the reference is not needed.
Add unset() right after the loop, to avoid reusing the reference.
1.2.1054.2. Specs¶
Short name |
Structures/DanglingArrayReferences |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Instant (5 mins) |
Precision |
High |
ClearPHP |
|
Examples |
|
Available in |
1.2.1055. Declare Static Once¶
Global and static variables should be declared only once in a method. It is also recommended to configure it at the beginning of the method. This could be refined by defining the variable at the last common moment, though it lacks readability.
<?php
function foo() {
if (rand(0, 1)) {
static $x;
++$x;
} else {
static $x;
--$x;
}
}
?>
Defining static or global methods late is a micro-optimisation.
1.2.1055.1. Suggestions¶
Remove duplicate static and global calls
Move the static and global calls to the beginning of the method
Refactor the static and global variable to properties
1.2.1055.2. Specs¶
Short name |
Structures/DeclareStaticOnce |
Rulesets |
|
Exakat since |
2.2.1 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Available in |
1.2.1056. Dereferencing String And Arrays¶
PHP allows the direct dereferencing of strings and arrays.
This was added in PHP 5.5. There is no need anymore for an intermediate variable between a string and array (or any expression generating such value) and accessing an index.
<?php
$x = array(4,5,6);
$y = $x[2] ; // is 6
May be replaced by
$y = array(4,5,6)[2];
$y = [4,5,6][2];
?>
1.2.1056.1. Specs¶
Short name |
Structures/DereferencingAS |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
5.3- |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1057. Die Exit Consistence¶
The analyzed code has less than 10% of one of them : for consistency reasons, it is recommended to make them all the same.
It happens that die or exit are used depending on coding style and files. One file may be consistently using exit, while the others are all using exit.
<?php
// be consistent
switch ($a) {
case 1 :
exit;
case 2 :
exit;
case 3 :
exit;
case 4 :
exit;
case 5 :
exit;
case 6 :
exit;
case 7 :
exit;
case 8 :
exit;
case 9 :
exit;
case 10 :
exit;
default :
die(); // Be consistent, always use the same.
}
?>
Using die or exit is also the target of other analysis.
1.2.1057.1. Specs¶
Short name |
Structures/DieExitConsistance |
Rulesets |
|
Exakat since |
0.8.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.1058. Difference Consistence¶
There are two operators to check a difference : <> and !=.
The analyzed code has less than 10% of one of them : for consistency reasons, it is recommended to make them all the same.
It happens that != and <> are used depending on coding style and files. One file may be consistently using <>, while the others are all using !=.
<?php
// Both != and <> are used in the code
// When one of them is used less than 10%, it is reported as a consistence issue.
if ($a != $b) {
} elseif ($c <> $d) {
}
?>
<> and != are the two only comparison operators that are identical.
See also Comparison Operators.
1.2.1058.1. Specs¶
Short name |
Structures/DifferencePreference |
Rulesets |
|
Exakat since |
0.11.1 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1059. __DIR__ Then Slash¶
__DIR__ must be concatenated with a string starting with /.
The magic constant __DIR__ holds the name of the current directory, without final /. When it is used to build path, then the following path fragment must start with /. Otherwise, two directories names will be merged together.
<?php
// __DIR__ = /a/b/c
// $filePath = /a/b/c/g.php
// /a/b/c/d/e/f.txt : correct path
echo __DIR__.'/d/e/f.txt';
echo dirname($filePath).'/d/e/f.txt';
// /a/b/cd/e/f.txt : most probably incorrect path
echo __DIR__.'d/e/f.txt';
echo dirname($filePath).'d/e/f.txt';
?>
1.2.1059.1. Suggestions¶
Add a check on __DIR__, as it may be ‘/’ when run at the root of the server
Add a ‘/’ at the beginning of the path after __DIR__.
Add a call to realpath() or file_exists(), before accessing the file.
1.2.1059.2. Specs¶
Short name |
Structures/DirThenSlash |
Rulesets |
|
Exakat since |
0.10.3 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Instant (5 mins) |
Precision |
Very high |
Examples |
|
Available in |
1.2.1060. Directly Use File¶
Some PHP functions have a close cousin that work directly on files : use them. This is faster and less code to write.
md5() => md5_file()
hash_hmac() => hash_mac_file()
<?php
// Good way
$file_hash = hash_file('sha512', 'example.txt');
// Slow way
$file_hash = hash('sha512', file_get_contents('example.txt'));
?>
See also hash_file.
1.2.1060.1. Suggestions¶
Use the _file() version of those functions
1.2.1060.2. Specs¶
Short name |
Structures/DirectlyUseFile |
Rulesets |
|
Exakat since |
1.5.5 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.1061. Don’t Be Too Manual¶
Adapt the examples from the PHP manual to your code. Don’t reuse directly the same names in your code : be more specific about what to expect in those variables.
<?php
// Search for phone numbers in a text
preg_match_all('/((\d{3})-(\d{3})-(\d{4}))/', $string, $phoneNumber);
// Search for phone numbers in a text
preg_match_all('/(\d{3})-(\d{3})-(\d{4})/', $string, $matches);
?>
1.2.1061.2. Specs¶
Short name |
Structures/DontBeTooManual |
Rulesets |
|
Exakat since |
1.6.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1062. Dont Change The Blind Var¶
When using a foreach(), the blind variables hold a copy of the original value. It is confusing to modify them, as it seems that the original value may be changed.
When actually changing the original value, use the reference in the foreach definition to make it obvious, and save the final reassignation.
When the value has to be prepared before usage, then save the filtered value in a separate variable. This makes the clean value obvious, and preserve the original value for a future usage.
<?php
// $bar is duplicated and kept
$foo = [1, 2, 3];
foreach($foo as $bar) {
// $bar is updated but its original value is kept
$nextBar = $bar + 1;
print $bar . ' => ' . ($nextBar) . PHP_EOL;
foobar($nextBar);
}
// $bar is updated and lost
$foo = [1, 2, 3];
foreach($foo as $bar) {
// $bar is updated but its final value is lost
print $bar . ' => ' . (++$bar) . PHP_EOL;
// Now that $bar is reused, it is easy to confuse its value
foobar($bar);
}
// $bar is updated and kept
$foo = [1, 2, 3];
foreach($foo as &$bar) {
// $bar is updated and keept
print $bar . ' => ' . (++$bar) . PHP_EOL;
foobar($bar);
}
?>
1.2.1062.1. Specs¶
Short name |
Structures/DontChangeBlindKey |
Rulesets |
|
Exakat since |
0.8.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1063. Dont Compare Typed Boolean¶
There is no need to compare explicitly a function call to a boolean, when the definition has a boolean return typehint.
The analysis checks for equality and identity comparisons. It doesn’t check for the not operator usage.
<?php
// Sufficient check
if (foo()) {
doSomething();
}
// Superfluous check
if (foo() === true) {
doSomething();
}
function foo() : bool {}
?>
1.2.1063.2. Specs¶
Short name |
Structures/DontCompareTypedBoolean |
Rulesets |
|
Exakat since |
2.1.5 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1064. Don’t Loop On Yield¶
Use
yield from, instead of looping on a generator withyield.
yield from delegate the yielding to another generator, and keep calling that generator until it is finished. It also works with implicit generator datastructure, like arrays.
<?php
function generator() {
for($i = 0; $i < 10; ++$i) {
yield $i;
}
}
function delegatingGenerator() {
yield from generator();
}
// Too much code here
function generator2() {
foreach(generator() as $g) {
yield $g;
}
}
?>
There is a performance gain when delegating, over looping manually on the generator. You may even consider writing the loop to store all values in an array, then yield from the array.
See also Generator delegation via yield from.
1.2.1064.1. Suggestions¶
Use yield from instead of the whole foreach() loop
1.2.1064.2. Specs¶
Short name |
Structures/DontLoopOnYield |
Rulesets |
|
Exakat since |
1.5.3 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1065. Dont Mix ++¶
++ operators, pre and post, have two distinct behaviors, and should be used separately.
When mixed in a larger expression, they are difficult to read, and may lead to unwanted behaviors.
<?php
// Clear and defined behavior
$i++;
$a[$i] = $i;
// The index is also incremented, as it is used AFTP the incrementation
// With $i = 2; $a is array(3 => 3)
$a[$i] = ++$i;
// $i is actually modified twice
$i = --$i + 1;
?>
1.2.1065.1. Suggestions¶
Extract the increment from the expression, and put it on a separate line.
See also and EXP30-C. Do not depend on the order of evaluation for side effects.
1.2.1065.2. Specs¶
Short name |
Structures/DontMixPlusPlus |
Rulesets |
|
Exakat since |
1.3.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1066. Don’t Read And Write In One Expression¶
Avoid giving value and using it at the same time, in one expression. This is an undefined behavior of PHP, and may change without warning.
One of those changes happens between PHP 7.2 and 7.3 :
<?php
$arr = [1];
$ref =& $arr[0];
var_dump($arr[0] + ($arr[0] = 2));
// PHP 7.2: int(4)
// PHP 7.3: int(3)
?>
See also UPGRADING 7.3.
1.2.1066.1. Suggestions¶
Split the expression in two separate expressions
1.2.1066.2. Specs¶
Short name |
Structures/DontReadAndWriteInOneExpression |
Rulesets |
|
Exakat since |
1.4.9 |
PHP Version |
All |
Severity |
Critical |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1067. Double Assignation¶
This happens when a container (variable, property, array index) is assigned with values twice in a row. One of them is probably a debug instruction, that was forgotten.
<?php
// Normal assignation
$a = 1;
// Double assignation
$b = 2;
$b = 3;
?>
1.2.1067.1. Specs¶
Short name |
Structures/DoubleAssignation |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1068. Double Instructions¶
Twice the same call in a row. This is worth a check.
<?php
// repetition of the same command, with the same effect each time.
$a = array_merge($b, $c);
$a = array_merge($b, $c);
// false positive : commands are identical, but the effect is compounded
$a = array_merge($a, $c);
$a = array_merge($a, $c);
?>
1.2.1068.1. Suggestions¶
Remove double work
Avoid repetition by using loops, variadic or quantifiers (dirname($path, 2))
1.2.1068.2. Specs¶
Short name |
Structures/DoubleInstruction |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.1069. Double Object Assignation¶
Make sure that assigning the same object to two variables is the intended purpose.
<?php
// $x and $y are the same object, as they both hold a reference to the same object.
// This means that changing $x, will also change $y.
$x = $y = new Z();
// $a and $b are distinct values, by default
$a = $b = 1;
?>
1.2.1069.1. Suggestions¶
Split the double assignation to two distinct instantiations
Split the double assignation to two distinct lines
1.2.1069.2. Specs¶
Short name |
Structures/DoubleObjectAssignation |
Rulesets |
|
Exakat since |
2.1.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1070. Drop Else After Return¶
Avoid else clause when the then clause returns, but not the else. And vice-versa.
This way, the else block disappears, and is now the main sequence of the function.
This is also true if else has a return, and then not. When doing so, don’t forget to reverse the condition.
<?php
// drop the else
if ($a) {
return $a;
} else {
doSomething();
}
// drop the then
if ($b) {
doSomething();
} else {
return $a;
}
// return in else and then
if ($a3) {
return $a;
} else {
$b = doSomething();
return $b;
}
?>
1.2.1070.1. Suggestions¶
Remove the else clause and move its code to the main part of the method
1.2.1071. Duplicate Calls¶
Duplicate calls within the same context. They should be called once, and then stashed in a variable for reuse. This saves a lot of time.
<?php
function foo($name) {
// The name decoration on the string is done twice. Once should be cached in a variable.
echo Hello,.ucfirst(strtolower($name)).<br />;
$query = 'Insert into visitors values (.ucfirst(strtolower($name)).)';
$res = $db->query($query);
}
?>
See also Constants and Userland naming Guide.
1.2.1071.1. Specs¶
Short name |
Structures/DuplicateCalls |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
ClearPHP |
|
Available in |
1.2.1072. Dynamic Calls¶
List of dynamic calls. They will probably need to be review manually.
<?php
$a = 'b';
// Dynamic call of a constant
echo constant($a);
// Dynamic variables
$$a = 2;
echo $b;
// Dynamic call of a function
$a('b');
// Dynamic call of a method
$object->$a('b');
// Dynamic call of a static method
A::$a('b');
?>
See also Variable functions.
1.2.1072.1. Specs¶
Short name |
Structures/DynamicCalls |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1073. Dynamic Code¶
List of instructions that were left during analysis, as they rely on dynamic data.
<?php
// Dynamic call to 'method';
$name = 'method';
$object->$name();
// Hard coded call to 'method';
$object->method();
?>
Any further analysis will need to start from here.
See also Variable functions.
1.2.1073.1. Specs¶
Short name |
Structures/DynamicCode |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1074. Echo Or Print¶
Echo and print have the same functional use. <?= and printf() are also considered in this analysis.
There seems to be a choice that is not enforced : one form is dominant, (> 90%) while the others are rare.
The analyzed code has less than 10% of one of the three : for consistency reasons, it is recommended to make them all the same.
It happens that print, echo or <?= are used depending on coding style and files. One file may be consistently using print, while the others are all using echo.
<?php
echo 'a';
echo 'b';
echo 'c';
echo 'd';
echo 'e';
echo 'f';
echo 'g';
echo 'h';
echo 'i';
echo 'j';
echo 'k';
// This should probably be written 'echo';
print 'l';
?>
1.2.1074.1. Specs¶
Short name |
Structures/EchoPrintConsistance |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1075. Echo With Concat¶
Optimize your
echo’s by not concatenating atechotime, but serving all argument separated. This will save PHP a memory copy.
If values, literals and variables, are small enough, this won’t have visible impact. Otherwise, this is less work and less memory waste.
<?php
echo $a, ' b ', $c;
?>
instead of
<?php
echo $a . ' b ' . $c;
echo $a b $c;
?>
1.2.1075.1. Suggestions¶
Turn the concatenation into a list of argument, by replacing the dots by commas.
1.2.1075.2. Specs¶
Short name |
Structures/EchoWithConcat |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
ClearPHP |
|
Examples |
|
Available in |
1.2.1076. Else If Versus Elseif¶
Always use elseif instead of else and if.
“The keyword elseif SHOULD be used instead of else if so that all control keywords look like single words”. Quoted from the PHP-FIG documentation
<?php
// Using elseif
if ($a == 1) { doSomething(); }
elseif ($a == 2) { doSomethingElseIf(); }
else { doSomethingElse(); }
// Using else if
if ($a == 1) { doSomething(); }
else if ($a == 2) { doSomethingElseIf(); }
else { doSomethingElse(); }
// Using else if, no {}
if ($a == 1) doSomething();
else if ($a == 2) doSomethingElseIf();
else doSomethingElse();
?>
See also elseif/else if.
1.2.1076.1. Suggestions¶
Merge else and if into elseif
Turn the else expression into a block, and have more than the second if in this block
Turn the if / else if / else into a switch structure
1.2.1076.2. Specs¶
Short name |
Structures/ElseIfElseif |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1077. Else Usage¶
Else should be avoided by various means. For example, defaulting values before, or short-circuiting the method as soon as the condition is not met.
<?php
// $a is always set
$a = 'default';
if ($condition) {
$a = foo($condition);
}
// Don't use else for default : set default before
if ($condition) {
$a = foo($condition);
} else {
$a = 'default';
}
// Use then to exit
if ( ! $condition) {
return;
}
$a = foo($condition);
// don't use else to return
if ($condition) {
$a = foo($condition);
} else {
return;
}
?>
See also Avoid Else, Return Early and Why does clean code forbid else expression.
1.2.1077.1. Specs¶
Short name |
Structures/ElseUsage |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1078. Empty Blocks¶
Full empty block, part of a control structures.
It is recommended to remove those blocks, so as to reduce confusion in the code.
<?php
foreach($foo as $bar) ; // This block seems erroneous
$foobar++;
if ($a === $b) {
doSomething();
} else {
// Empty block. Remove this
}
// Blocks containing only empty expressions are also detected
for($i = 0; $i < 10; $i++) {
;
}
// Although namespaces are not control structures, they are reported here
namespace A;
namespace B;
?>
1.2.1078.1. Suggestions¶
Fill the block with a command
Fill the block with a comment that explain the situation
Remove the block and its commanding operator
1.2.1078.2. Specs¶
Short name |
Structures/EmptyBlocks |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1079. Empty Instructions¶
Empty instructions are part of the code that have no instructions.
This may be trailing semi-colon or empty blocks for if-then structures.
Comments that explains the reason of the situation are not taken into account.
<?php
$condition = 3;;;;
if ($condition) { }
?>
1.2.1079.2. Specs¶
Short name |
Structures/EmptyLines |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1080. Empty Try Catch¶
The code does try, then catch errors but do no act upon the error.
<?php
try {
doSomething();
} catch (Throwable $e) {
// ignore this
}
?>
At worst, the error should be logged, so as to measure the actual usage of the catch expression.
catch( Exception $e) (PHP 5) or catch(`Throwable <https://www.php.net/manual/en/class.throwable.php>`_ $e) with empty catch block should be banned. They ignore any error and proceed as if nothing happened. At worst, the event should be logged for future analysis.
See also Empty Catch Clause.
1.2.1080.1. Suggestions¶
Add some logging in the catch
Add a comment to mention why the catch is empty
Change the exception, chain it and throw again
1.2.1080.2. Specs¶
Short name |
Structures/EmptyTryCatch |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1081. Empty With Expression¶
<?php
// PHP 5.5+ empty() usage
if (empty(strtolower($b . $c))) {
doSomethingWithoutA();
}
// Compatible empty() usage
$a = strtolower($b . $c);
if (empty($a)) {
doSomethingWithoutA();
}
?>
See also empty.
1.2.1081.1. Suggestions¶
Use the compatible syntax, and store the result in a local variable before testing it with empty
1.2.1081.2. Specs¶
Short name |
Structures/EmptyWithExpression |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
5.5+ |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1082. Error Messages¶
Error message when an error is reported in the code. Those messages will be read by whoever is triggering the error, and it has to be helpful.
It is a good exercise to read the messages out of context, and try to understand what is about.
<?php
// Not so helpful messages
die('Here be monsters');
exit('An error happened');
throw new Exception('Exception thrown at runtime');
?>
Error messages are spotted via die, exit or throw.
1.2.1082.1. Specs¶
Short name |
Structures/ErrorMessages |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1083. error_reporting() With Integers¶
Using named constants with error_reporting is strongly encouraged to ensure compatibility for future versions. As error levels are added, the range of integers increases, so older integer-based error levels will not always behave as expected. (Adapted from the documentation).
<?php
// This is ready for PHP next version
error_reporting(E_ALL & ~E_DEPRECATED & ~E_STRICT & ~E_NOTICE & ~E_WARNING);
// This is not ready for PHP next version
error_reporting(2047);
// -1 and 0 are omitted, as they will be valid even is constants changes.
error_reporting(-1);
error_reporting(0);
?>
See also directive error_reporting and error_reporting.
1.2.1083.1. Suggestions¶
Always use the constant combination when configuring error_reporting or any PHP native function
1.2.1083.2. Specs¶
Short name |
Structures/ErrorReportingWithInteger |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1084. Eval() Usage¶
Using eval() is evil.
Using eval() is bad for performances (compilation time), for caches (it won’t be compiled), and for security (if it includes external data).
<?php
// Avoid using incoming data to build the eval() expression : any filtering error leads to PHP injection
$mathExpression = $_GET['mathExpression'];
$mathExpression = preg_replace('#[^0-9+\-*/\(/)]#is', '', $mathExpression); // expecting 1+2
$literalCode = '$a = '.$mathExpression.';';
eval($literalCode);
echo $a;
// If the code code given to eval() is known at compile time, it is best to put it inline
$literalCode = 'phpinfo();';
eval($literalCode);
?>
Most of the time, it is possible to replace the code by some standard PHP, like variable variable for accessing a variable for which you have the name. At worse, including a pregenerated file is faster and cacheable.
There are several situations where eval() is actually the only solution :
For PHP 7.0 and later, it is important to put eval() in a try..catch expression.
See also eval and The Land Where PHP Uses `eval() <https://www.exakat.io/land-where-php-uses-eval/>`_.
1.2.1084.1. Suggestions¶
Use a dynamic feature of PHP to replace the dynamic code
Store the code on the disk, and use include
Replace create_function() with a closure!
1.2.1084.2. Specs¶
Short name |
Structures/EvalUsage |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
ClearPHP |
|
Examples |
|
Available in |
1.2.1085. eval() Without Try¶
eval()emits aParseErrorexception with PHP 7 and later. Catching this exception is the recommended way to handle errors when using theeval()function.
<?php
$code = 'This is no PHP code.';
//PHP 5 style
eval($code);
// Ends up with a Fatal error, at execution time
//PHP 7 style
try {
eval($code);
} catch (ParseError $e) {
cleanUpAfterEval();
}
?>
Note that it will catch situations where eval() is provided with code that can’t be used, but it will not catch security problems. Avoid using eval() with incoming data.
1.2.1085.1. Suggestions¶
Always add a try/catch block around eval() call
1.2.1085.2. Specs¶
Short name |
Structures/EvalWithoutTry |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
7.0+ |
Severity |
Critical |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1086. Exit() Usage¶
Using exit or die() <https://www.php.net/`die>`_ in the code makes the code untestable (it will break unit tests). Moreover, if there is no reason or string to display, it may take a long time to spot where the application is stuck.
<?php
// Throw an exception, that may be caught somewhere
throw new \Exception('error');
// Dying with error message.
die('error');
function foo() {
//exiting the function but not dying
if (somethingWrong()) {
return true;
}
}
?>
Try exiting the function/class with return, or throw exception that may be caught later in the code.
1.2.1086.1. Suggestions¶
Avoid exit and die. Let the script finish.
Throw an exception and let it be handled before finishing
1.2.1086.2. Specs¶
Short name |
Structures/ExitUsage |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
ClearPHP |
|
Examples |
|
Available in |
1.2.1087. Failed Substr Comparison¶
The extracted string must be of the size of the compared string.
This is also true for negative lengths.
<?php
// Possible comparison
if (substr($a, 0, 3) === 'abc') { }
if (substr($b, 4, 3) === 'abc') { }
// Always failing
if (substr($a, 0, 3) === 'ab') { }
if (substr($a, 3, -3) === 'ab') { }
// Omitted in this analysis
if (substr($a, 0, 3) !== 'ab') { }
?>
1.2.1087.1. Suggestions¶
Fix the string
Fix the length of the string
Put the string in a constant, and use strlen() or mb_strlen()
1.2.1087.2. Specs¶
Short name |
Structures/FailingSubstrComparison |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1088. Switch Fallthrough¶
A switch with fallthrough is prone to errors.
A fallthrough happens when a case or default clause in a switch statement is not finished by a break (or equivalent); CWE report this as a security concern, unless well documented.
A fallthrough may be used as a feature. Then, it is indistinguishable from an error.
When the case block is empty, this analysis doesn’t report it : the case is then used as an alias.
<?php
switch($variable) {
case 1 : // case 1 is not reported, as it actually shares the same body as case 33
case 33 :
break ;
case 2 :
break ;
default:
++$a;
case 4 :
break ;
}
?>
This analysis doesn’t take into account comments about the fallthrough.
See also CWE-484: Omitted `Break Statement in Switch <https://cwe.mitre.org/data/definitions/484.html>`_ and Rule: no-switch-case-fall-through.
1.2.1088.1. Suggestions¶
Make separate code for each case. Always use break at the end of a case or default.
1.2.1088.2. Specs¶
Short name |
Structures/Fallthrough |
Rulesets |
|
Exakat since |
0.12.14 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.1089. File Uploads¶
This code makes usage of file upload features of PHP.
Upload file feature is detected through the usage of specific functions :
<?php
$uploaddir = '/var/www/uploads/';
$uploadfile = $uploaddir . basename($_FILES['userfile']['name']);
echo '<pre>';
if (move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile)) {
echo 'File is valid, and was successfully uploaded.'.PHP_EOL;
} else {
echo 'Possible file upload attack!'.PHP_EOL;
}
echo 'Here is some more debugging info:';
print_r($_FILES);
print '</pre>';
?>
See also Handling file uploads.
1.2.1089.1. Specs¶
Short name |
Structures/FileUploadUsage |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1090. File Usage¶
The application makes usage of files on the system (read, write, delete, etc.).
Files usage is based on the usage of file functions.
<?php
$fp = fopen('/tmp/file.txt', 'w+');
// ....
?>
See also filesystem.
1.2.1090.1. Specs¶
Short name |
Structures/FileUsage |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1091. For Using Functioncall¶
It is recommended to avoid functioncall in the for() statement.
<?php
// Fastest way
$nb = count($array);
for($i = 0; $i < $nb; ++$i) {
doSomething($i);
}
// Same as above, but slow
for($i = 0; $i < count($array); ++$i) {
doSomething($i);
}
// Same as above, but slow
foreach($portions as &$portion) {
// here, array_sum() doesn't depends on the $grade. It should be out of the loop
$portion = $portion / array_sum($portions);
}
$total = array_sum($portion);
foreach($portion as &$portion) {
$portion = $portion / $total;
}
?>
This is true with any kind of functioncall that returns the same value throughout the loop.
Make sure that the functioncall doesn’t change with the loop :
See also PHP for loops and counting arrays.
1.2.1091.1. Suggestions¶
Call the function once, before the loop
Replace by a foreach structure
1.2.1091.2. Specs¶
Short name |
Structures/ForWithFunctioncall |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
ClearPHP |
|
Available in |
1.2.1092. Foreach Needs Reference Array¶
When using foreach with a reference as value, the source must be a referenced array, which is a variable (or array or property or static property).
When the array is the result of an expression, the array is not kept in memory after the foreach loop, and any change made with & are lost.
This will do nothing
<?php
foreach(array(1,2,3) as &$value) {
$value *= 2;
}
?>
This will have an actual effect
<?php
$array = array(1,2,3);
foreach($array as &$value) {
$value *= 2;
}
?>
1.2.1092.1. Specs¶
Short name |
Structures/ForeachNeedReferencedSource |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1093. Foreach Reference Is Not Modified¶
Foreach statement may loop using a reference, especially when the loop has to change values of the array it is looping on.
In the spotted loop, reference are used but never modified. They may be removed.
<?php
$letters = range('a', 'z');
// $letter is not used here
foreach($letters as &$letter) {
$alphabet .= $letter;
}
// $letter is actually used here
foreach($letters as &$letter) {
$letter = strtoupper($letter);
}
?>
1.2.1093.1. Suggestions¶
Remove the reference from the foreach
Actually modify the content of the reference
1.2.1093.2. Specs¶
Short name |
Structures/ForeachReferenceIsNotModified |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1094. Overwritten Source And Value¶
In a foreach(), it is best to keep source and values distinct. Otherwise, they overwrite each other.
Since PHP 7.0, PHP makes a copy of the original source, then works on it. This makes possible to use the same name for the source and the values.
<?php
// displays 0-1-2-3-3
$array = range(0, 3);
foreach($array as $array) {
print $array . '-';
}
print_r($array);
/* displays 0-1-2-3-Array
(
[0] => 0
[1] => 1
[2] => 2
[3] => 3
)
*/
$array = range(0, 3);
foreach($array as $v) {
print $v . '-';
}
print_r($array);
?>
When the source is used as the value, the elements in the array are successively assigned to itself. After the loop, the original array has been replaced by its last element.
The same applies to the index, or to any variable in a list() structure, used in a foreach().
1.2.1094.1. Suggestions¶
Keep the source, the index and the values distinct
1.2.1094.2. Specs¶
Short name |
Structures/ForeachSourceValue |
Rulesets |
|
Exakat since |
1.8.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1095. Foreach With list()¶
Foreach loops have the ability to use list() (or []) as blind variables. This syntax assign directly array elements to various variables.
PHP 5.5 introduced the usage of list in foreach() loops. Until PHP 7.1, it was not possible to use non-numerical arrays as list() wouldn’t support string-indexed arrays.
<?php
// PHP 5.5 and later, with numerically-indexed arrays
foreach($array as list($a, $b)) {
// do something
}
// PHP 7.1 and later, with arrays
foreach($array as list('col1' => $a, 'col3' => $b)) { // 'col2 is ignored'
// do something
}
?>
Previously, it was compulsory to extract() the data from the blind array :
<?php
foreach($array as $c) {
list($a, $b) = $c;
// do something
}
?>
See also The list function & practical uses of array destructuring in PHP and Array destructuring in PHP.
1.2.1095.1. Specs¶
Short name |
Structures/ForeachWithList |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
With PHP 5.5 and more recent |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
Very high |
Available in |
1.2.1096. Forgotten Whitespace¶
Forgotten whitespaces only bring misery to the code.
White spaces have been left at either end of a file : before the PHP opening tag, or after the closing tag.
Usually, such whitespaces are forgotten, and may end up summoning the infamous ‘headers already sent’ error. It is better to remove them.
<?php
// This script has no forgotten whitespace, not at the beginning
function foo() {}
// This script has no forgotten whitespace, not at the end
?>
See also How to fix Headers already sent error in PHP.
1.2.1096.1. Suggestions¶
Remove all whitespaces before and after a script. This doesn’t apply to template, which may need to use those spaces.
Remove the final tag, to prevent any whitespace to be forgotten at the end of the file. This doesn’t apply to the opening PHP tag, which is always necessary.
1.2.1096.2. Specs¶
Short name |
Structures/ForgottenWhiteSpace |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.1097. Function Subscripting, Old Style¶
Since PHP 5.4, it is now possible use function results as an array, and access directly its element :
<?php
function foo() {
return array(1 => 'a', 'b', 'c');
}
echo foo()[1]; // displays 'a';
// Function subscripting, the old way
function foo() {
return array(1 => 'a', 'b', 'c');
}
$x = foo();
echo $x[1]; // displays 'a';
?>
1.2.1097.1. Suggestions¶
Skip the local variable and directly use the return value from the function
1.2.1097.2. Specs¶
Short name |
Structures/FunctionPreSubscripting |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
With PHP 5.4 and more recent |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1098. Function Subscripting¶
It is possible to use the result of a methodcall directly as an array, without storing the result in a temporary variable.
This works, given that the method actually returns an array.
This syntax was not possible until PHP 5.4. Until then, it was compulsory to store the result in a variable first. Although this is now superfluous, it has been a standard syntax in PHP, and is still being used.
<?php
function foo() {
return array(1 => 'a', 'b', 'c');
}
echo foo()[1]; // displays 'a';
// Function subscripting, the old way
function foo() {
return array(1 => 'a', 'b', 'c');
}
$x = foo();
echo $x[1]; // displays 'a';
?>
Storing the result in a variable is still useful if the result is actually used more than once. See also and Accessing array elements with square bracket syntax.
1.2.1098.1. Specs¶
Short name |
Structures/FunctionSubscripting |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
With PHP 5.4 and more recent |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.1099. Global In Global¶
List of global variables. There are the global variables, defined with the global keyword, and the implicit global variables, defined in the global scope.
<?php
global $explicitGlobal; // in global namespace
$implicitGlobal = 1; // in global namespace, variables are automatically global
function foo() {
global $explicitGlobalInFoo; // in functions, globals must be declared with global
}
?>
See also Variable Scope.
1.2.1099.1. Specs¶
Short name |
Structures/GlobalInGlobal |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1100. Global Inside Loop¶
The global and static keywords must be used outside loops. Otherwise, they are evaluated at each loop, slowing the whole process.
<?php
// Here, global is used once
global $total;
foreach($a as $b) {
$total += $b;
}
// Global is called each time : this is slow.
foreach($a as $b) {
global $total;
$total += $b;
}
?>
This is a micro-optimisation.
1.2.1100.2. Specs¶
Short name |
Structures/GlobalOutsideLoop |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Available in |
1.2.1101. Global Usage¶
List usage of globals variables, with global keywords or direct access to $GLOBALS.
<?php
$a = 1; /* global scope */
function test()
{
echo $a; /* reference to local scope variable */
}
test();
?>
It is recommended to avoid using global variables, at it makes it very difficult to track changes in values across the whole application.
See also Variable scope.
1.2.1101.1. Specs¶
Short name |
Structures/GlobalUsage |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
ClearPHP |
|
Available in |
1.2.1102. Find Key Directly¶
No need for a foreach() to search for a key.
PHP offers two solutions : array_search() and array_keys(). Array_search() finds the first key that fits a value, and array_keys returns all the keys.
<?php
$array = ['a', 'b', 'c', 'd', 'e'];
print array_search($array, 'c');
// print 2 => 'c';
print_r(array_keys($array, 'c'));
// print 2 => 'c';
?>
See also array_search and array_keys.
1.2.1102.1. Specs¶
Short name |
Structures/GoToKeyDirectly |
Rulesets |
|
Exakat since |
1.1.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.1103. Comparisons Orientation¶
Maths has two comparisons styles :
>or<. Both may include equality :<=and>=.
The analyzed code has less than 10% of one of them : for consistency reasons, it is recommended to make them all the same.
It is recommended to always use the same comparison style.
<?php
// Always compare in the same direction
if ($a > $c) {
} elseif ($c > $b) {
} else {
// equality case
}
// Alterning comparison style lead to harder to read code
if ($b > 3) {
} elseif ($b < 3) {
}
?>
See also and Comparison Operators.
1.2.1103.1. Specs¶
Short name |
Structures/GtOrLtFavorite |
Rulesets |
|
Exakat since |
1.3.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1104. Heredoc Delimiter¶
Heredoc and Nowdoc expressions may use a variety of delimiters.
There seems to be a standard delimiter in the code, and some exceptions : one or several forms are dominant (> 90%), while the others are rare.
The analyzed code has less than 10% of the rare delimiters. For consistency reasons, it is recommended to make them all the same.
Generally, one or two delimiters are used, with generic value. It is recommended to use a humanly readable delimiter : SQL, HTML, XML, GREMLIN, etc. This helps readability in the code.
<?php
echo <<<SQL
SELECT * FROM table1;
SQL;
echo <<<SQL
SELECT * FROM table2;
SQL;
echo <<<SQL
SELECT * FROM table3;
SQL;
echo <<<SQL
SELECT * FROM table4;
SQL;
echo <<<SQL
SELECT * FROM table5;
SQL;
echo <<<SQL
SELECT * FROM table11;
SQL;
echo <<<SQL
SELECT * FROM table12;
SQL;
echo <<<SQL
SELECT * FROM table13;
SQL;
// Nowdoc
echo <<<'SQL'
SELECT * FROM table14;
SQL;
echo <<<SQL
SELECT * FROM table15;
SQL;
echo <<<HEREDOC
SELECT * FROM table215;
HEREDOC;
?>
1.2.1104.1. Specs¶
Short name |
Structures/HeredocDelimiterFavorite |
Rulesets |
|
Exakat since |
0.12.0 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1105. Htmlentities Calls¶
htmlentities() and htmlspecialchars() are used to prevent injecting special characters in HTML code. As a bare minimum, they take a string and encode it for HTML.
The second argument of the functions is the type of protection. The protection may apply to quotes or not, to HTML 4 or 5, etc. It is highly recommended to set it explicitly.
The third argument of the functions is the encoding of the string. In PHP 5.3, it is ISO-8859-1, in 5.4, was UTF-8, and in 5.6, it is now default_charset, a php.ini configuration that has the default value of UTF-8. It is highly recommended to set this argument too, to avoid distortions from the configuration.
<?php
$str = 'A quote is <b>bold</b>';
// Outputs, without depending on the php.ini: A 'quote' is <b>bold</b>
echo htmlentities($str, ENT_QUOTES, 'UTF-8');
// Outputs, while depending on the php.ini: A quote is <b>bold</b>
echo htmlentities($str);
?>
Also, note that arguments 2 and 3 are constants and string, respectively, and should be issued from the list of values available in the manual. Other values than those will make PHP use the default values.
See also htmlentities and htmlspecialchars.
1.2.1105.1. Suggestions¶
Always use the third argument with htmlentities()
1.2.1105.2. Specs¶
Short name |
Structures/Htmlentitiescall |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.1106. Htmlentities Using Default Flag¶
htmlspecialchars(), htmlentities(), htmlspecialchars_decode(), html_entity_decode() and get_html_translation_table(), are used to prevent injecting special characters in HTML code. As a bare minimum, they take a string and encode it for HTML.
The second argument of the functions is the type of protection. The protection may apply to quotes or not, to HTML 4 or 5, etc. It is highly recommended to set it explicitly.
In PHP 8.1, the default value of this parameter has changed. It used to be ENT_COMPAT and is now ENT_QUOTES | ENT_SUBSTITUTE. The main difference between the different configuration is that the single quote, which was left intact so far, is now protected HTML style.
<?php
$str = 'A quote in <b>bold</b> : \' and ';
// PHP 8.0 outputs, without depending on the php.ini: A quote in <b>bold</b> : ' and "
echo htmlentities($str);
// PHP 8.1 outputs, while depending on the php.ini: A quote in <b>bold</b> : ' and "
echo htmlentities($str);
?>
See also htmlentities and htmlspecialchars.
1.2.1106.1. Suggestions¶
Always use the second argument to explicitely set the desired protection
1.2.1106.2. Specs¶
Short name |
Structures/HtmlentitiescallDefaultFlag |
Rulesets |
|
Exakat since |
2.2.3 |
PHP Version |
With PHP 8.1 and more recent |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1107. Identical Conditions¶
These logical expressions contain members that are identical.
This means those expressions may be simplified.
<?php
// twice $a
if ($a || $b || $c || $a) { }
// Hiding in parenthesis is bad
if (($a) ^ ($a)) {}
// expressions may be large
if ($a === 1 && 1 === $a) {}
?>
1.2.1107.1. Suggestions¶
Merge the two structures into one unique test
Add extra expressions between the two structures
Nest the structures, to show that different attempts are made
1.2.1107.2. Specs¶
Short name |
Structures/IdenticalConditions |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Critical |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1108. Identical Consecutive Expression¶
Identical consecutive expressions are worth being checked.
They may be a copy/paste with unmodified content. When the content has to be duplicated, it is recommended to avoid executing the expression again, and just access the cached result.
<?php
$current = $array[$i];
$next = $array[$i + 1];
$nextnext = $array[$i + 1]; // OOps, nextnext is wrong.
// Initialization
$previous = foo($array[1]); // previous is initialized with the first value on purpose
$next = foo($array[1]); // the second call to foo() with the same arguments should be avoided
// the above can be rewritten as :
$next = $previous; // save the processing.
for($i = 1; $i < 200; ++$i) {
$next = doSomething();
}
?>
1.2.1108.1. Specs¶
Short name |
Structures/IdenticalConsecutive |
Rulesets |
|
Exakat since |
1.0.8 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.1109. Identical On Both Sides¶
Operands should be different when comparing or making a logical combination. Of course, the value each operand holds may be identical. When the same operand appears on both sides of the expression, the result is know before execution.
<?php
// Trying to confirm consistency
if ($login == $login) {
doSomething();
}
// Works with every operators
if ($object->login( ) !== $object->login()) {
doSomething();
}
if ($sum >= $sum) {
doSomething();
}
//
if ($mask && $mask) {
doSomething();
}
if ($mask || $mask) {
doSomething();
}
?>
1.2.1109.1. Suggestions¶
Remove one of the alternative, and remove the logical link
Modify one of the alternative, and make it different from the other
1.2.1109.2. Specs¶
Short name |
Structures/IdenticalOnBothSides |
Rulesets |
|
Exakat since |
1.0.8 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1110. If With Same Conditions¶
Successive If / then structures that have the same condition may be either merged or have one of the condition changed.
<?php
if ($a == 1) {
doSomething();
}
if ($a == 1) {
doSomethingElse();
}
// May be replaced by
if ($a == 1) {
doSomething();
doSomethingElse();
}
?>
Note that if the values used in the condition have been modified in the first if/then structure, the two distinct conditions may be needed.
<?php
// May not be merged
if ($a == 1) {
// Check that this is really the situation
$a = checkSomething();
}
if ($a == 1) {
doSomethingElse();
}
?>
1.2.1110.1. Suggestions¶
Merge the two conditions so the condition is used once.
Change one of the condition, so they are different
Make it obvious that the first condition is a try, preparing the normal conditions.
1.2.1110.2. Specs¶
Short name |
Structures/IfWithSameConditions |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1111. Iffectations¶
Affectations that appears in a condition.
Iffectations are a way to do both a test and an affectations. They may also be typos, such as if ($x = 3) { … }, leading to a constant condition.
<?php
// an iffectation : assignation in a If condition
if($connexion = mysql_connect($host, $user, $pass)) {
$res = mysql_query($connexion, $query);
}
// Iffectation may happen in while too.
while($row = mysql_fetch($res)) {
$store[] = $row;
}
?>
1.2.1111.1. Suggestions¶
Move the assignation inside the loop, and make an existence test in the condition.
Move the assignation before the if/then, make an existence test in the condition.
1.2.1111.2. Specs¶
Short name |
Structures/Iffectation |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Available in |
1.2.1112. Implicit Global¶
Global variables, that are used in local scope with global keyword, but are not declared as global in the global scope. They may be mistaken with distinct values, while, in PHP, variables in the global scope are truly global.
<?php
// This is implicitely global
$implicitGlobal = 1;
global $explicitGlobal;
$explicitGlobal = 2;
foo();
echo $explicitFunctionGlobal;
function foo() {
// This global is needed, but not the one in the global space
global $implicitGlobal, $explicitGlobal, $explicitFunctionGlobal;
// This won't be a global, as it must be 'global' in a function scope
$notImplicitGlobal = 3;
$explicitFunctionGlobal = 3;
}
?>
1.2.1112.1. Specs¶
Short name |
Structures/ImplicitGlobal |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1113. Implied If¶
It is confusing to emulate if/then with boolean operators.
It is possible to emulate a if/then structure by using the operators ‘and’ and ‘or’. Since optimizations will be applied to them : when the left operand of ‘and’ is false, the right one is not executed, as its result is useless; when the left operand of ‘or’ is true, the right one is not executed, as its result is useless;
However, such structures are confusing. It is easy to misread them as conditions, and ignore an important logic step.
<?php
// Either connect, or die
mysql_connect('localhost', $user, $pass) or die();
// Defines a constant if not found.
defined('SOME_CONSTANT') and define('SOME_CONSTANT', 1);
// Defines a default value if provided is empty-ish
// Warning : this is
$user = $_GET['user'] || 'anonymous';
?>
It is recommended to use a real ‘if then’ structures, to make the condition readable.
1.2.1113.1. Suggestions¶
Replace this expression by an explicit if-then structure
1.2.1113.2. Specs¶
Short name |
Structures/ImpliedIf |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Instant (5 mins) |
Precision |
High |
ClearPHP |
|
Available in |
1.2.1114. Implode() Arguments Order¶
implode() accepted two signatures, but is only recommending one. Both types orders of string then array, and array then string have been possible until PHP 7.4.
In PHP 7.4, the order array then string is deprecated, and emits a warning. It will be removed in PHP 8.0.
<?php
$glue = ',';
$pieces = range(0, 4);
// documented argument order
$s = implode($glue, $pieces);
// Pre 7.4 argument order
$s = implode($pieces, $glue);
// both produces 0,1,2,3,4
?>
1.2.1114.2. Specs¶
Short name |
Structures/ImplodeArgsOrder |
Rulesets |
|
Exakat since |
1.9.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1115. Inclusions¶
List of all inclusions. Inclusions are made with include(), include_once(), require() and require_once().
<?php
include 'library.php';
// display is a function defined in 'library.php';
display('Message');
?>
1.2.1115.1. Specs¶
Short name |
Structures/IncludeUsage |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
Very high |
Available in |
1.2.1116. Inconsistent Concatenation¶
Concatenations happens within a string or using the dot operator. Using both is an inconsistent way of writing concatenations.
Switching methods of concatenation, sometimes in the same expression, is error prone. The reader gets confused, and may miss important information.
<?php
//Concatenation
$consistent = $a . 'b'. $c;
//Interpolation
$consistentToo = "{$a}b$c";
// Concatenation and interpolation
$inconsistent = $a . "b$c";
// Concatenation and interpolation too
$consistentThree = <<<CONSISTENT
{$a}b$c
CONSISTENT;
// Concatenation and interpolation collisions
$collision = theClass::CONSTANTE . "b{$c}".number_format($t, 2).' $CAD'.\n;
?>
There are some situations where using concatenation are compulsory : when calling a constant, or a function, or make use of the escape sequence. Those are ignored in this analysis.
1.2.1116.1. Specs¶
Short name |
Structures/InconsistentConcatenation |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1117. Inconsistent Elseif¶
Chaining if/elseif requires a consistent string of conditions. The conditions are executed one after the other, and the conditions shouldn’t overlap.
This analysis reports chains of elseif that don’t share a common variable (or array, or property, etc.. ). As such, testing different conditions are consistent.
<?php
// $a is always common, so situations are mutually exclusive
if ($a === 1) {
doSomething();
} else if ($a > 1) {
doSomethingElse();
} else {
doSomethingDefault();
}
// $a is always common, so situations are mutually exclusive
// although, it may be worth checking the consistency here
if ($a->b === 1) {
doSomething();
} else if ($a->c > 1) {
doSomethingElse();
} else {
doSomethingDefault();
}
// if $a === 1, then $c doesn't matter?
// This happens, but then logic doesn't appear in the code.
if ($a === 1) {
doSomething();
} else if ($c > 1) {
doSomethingElse();
} else {
doSomethingDefault();
}
?>
1.2.1117.1. Specs¶
Short name |
Structures/InconsistentElseif |
Rulesets |
|
Exakat since |
1.4.3 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1118. Indices Are Int Or String¶
Indices in an array notation such as
$array['indice']may only be integers or string.
Boolean, Null or float will be converted to their integer or string equivalent.
<?php
$a = [true => 1,
1.0 => 2,
1.2 => 3,
1 => 4,
'1' => 5,
0.8 => 6,
0x1 => 7,
01 => 8,
null => 1,
'' => 2,
false => 1,
0 => 2,
'0.8' => 3,
'01' => 4,
'2a' => 5
];
print_r($a);
/*
The above displays
Array
(
[1] => 8
[0] => 2
[] => 2
[0.8] => 3
[01] => 4
[2a] => 5
)
*/
?>
Decimal numbers are rounded to the closest integer; Null is transtyped to ‘’ (empty string); true is 1 and false is 0; Integers in strings are transtyped, while partial numbers or decimals are not analyzed in strings.
As a general rule of thumb, only use integers or strings that don't look like integers.
This analyzer may find constant definitions, when available.
Note also that PHP detects integer inside strings, and silently turn them into integers. Partial and octal numbers are not transformed.
<?php
$a = [1 => 1,
'2' => 2,
'011' => 9, // octal number
'11d' => 11, // partial number
];
var_dump($a);
/*
The above displays
array(4) {
[1]=>
int(1)
[2]=>
int(2)
[011]=>
int(9)
[11d]=>
int(11)
}*/
?>
See also Arrays syntax.
1.2.1118.1. Suggestions¶
Do not use any type but string or integer
Force typecast the keys when building an array
1.2.1118.2. Specs¶
Short name |
Structures/IndicesAreIntOrString |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1119. Infinite Recursion¶
A method is calling itself, with unchanged arguments. This will probably repeat indefinitely.
This applies to recursive functions without any condition. This also applies to function which inject the incoming arguments, without modifications.
<?php
function foo($a, $b) {
if ($a > 10) {
return;
}
foo($a, $b);
}
function foo2($a, $b) {
++$a; // $a is modified
if ($a > 10) {
return;
}
foo2($a, $b);
}
?>
1.2.1119.1. Suggestions¶
Modify arguments before injecting them again in the same method
Use different values when calling the same method
1.2.1119.2. Specs¶
Short name |
Structures/InfiniteRecursion |
Rulesets |
|
Exakat since |
1.8.6 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1120. Invalid Pack Format¶
Some characters are invalid in a pack() format string.
pack() and unpack() accept the following format specifiers : aAhHcCsSnviIlLNVqQJPfgGdeExXZ.
unpack() also accepts a name after the format specifier and an optional quantifier.
All other situations is not a valid, and produces a warning : pack(): Type t: unknown format code
<?php
$binarydata = pack(nvc*, 0x1234, 0x5678, 65, 66);
// the first unsigned short is stored as 'first'. The next matches are names with numbers.
$res = unpack('nfirst/vc*', $binarydata);
?>
Check pack() documentation for format specifiers that were introduced in various PHP version, namely 7.0, 7.1 and 7.2.
1.2.1120.1. Suggestions¶
Fix the packing format with correct values
1.2.1120.2. Specs¶
Short name |
Structures/InvalidPackFormat |
Rulesets |
|
Exakat since |
1.4.9 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1121. Invalid Regex¶
The PCRE regex doesn’t compile. It isn’t a valid regex.
Several reasons may lead to this situation : syntax error, Unknown modifier, missing parenthesis or reference.
<?php
// valid regex
preg_match('/[abc]/', $string);
// invalid regex (missing terminating ] for character class
preg_match('/[abc/', $string);
?>
Regex are check with the Exakat version of PHP.
Dynamic regex are only checked for simple values. Dynamic values may eventually generate a compilation error.
1.2.1121.2. Specs¶
Short name |
Structures/InvalidRegex |
Rulesets |
|
Exakat since |
1.0.5 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1122. Is Actually Zero¶
This addition actually may be simplified because one term is actually negated by another.
This kind of error happens when the expression is very large : the more terms are included, the more chances are that some auto-annihilation happens.
This error may also be a simple typo : for example, calculating the difference between two consecutive terms.
<?php
// This is quite obvious
$a = 2 - 2;
// This is obvious too. This may be a typo-ed difference between two consecutive terms.
// Could have been $c = $fx[3][4] - $fx[3][3] or $c = $fx[3][5] - $fx[3][4];
$c = $fx[3][4] - $fx[3][4];
// This is less obvious
$a = $b[3] - $c + $d->foo(1,2,3) + $c + $b[3];
?>
1.2.1122.1. Suggestions¶
Clean the code and remove the null sum
Fix one of the variable : this expression needs another variable here
When adding differences, calculate the difference in a temporary variable first.
See also and .
1.2.1122.2. Specs¶
Short name |
Structures/IsZero |
Rulesets |
|
Exakat since |
0.12.15 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1123. isset() With Constant¶
Until PHP 7, it was possible to use arrays as constants, but it was not possible to test them with isset.
<?php
const X = [1,2,3];
if (isset(X[4])) {}
?>
This would yield an error : Cannot use `isset() <https://www.www.php.net/isset>`_ on the result of an expression (you can use "null !== expression" instead). This is a backward incompatibility.
1.2.1123.2. Specs¶
Short name |
Structures/IssetWithConstant |
Rulesets |
CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, All |
Exakat since |
0.8.4 |
PHP Version |
With PHP 7.0 and more recent |
Severity |
Major |
Time To Fix |
Instant (5 mins) |
Precision |
Very high |
Available in |
1.2.1124. Use json_decode() Options¶
json_decode() returns objects by default, unless the second argument is set to
TRUEorJSON_OBJECT_AS_ARRAY. Then, it returns arrays.
Avoid casting the returned value from json_decode(), and use the second argument to directly set the correct type.
<?php
$json = '{a:b}';
// Good syntax
$array = json_decode($json, JSON_OBJECT_AS_ARRAY);
// GoToo much work
$array = (array) json_decode($json);
?>
Note that all objects will be turned into arrays, recursively. If you’re expecting an array of objects, don’t use the JSON_OBJECT_AS_ARRAY constant, and change your JSON code.
Note that JSON_OBJECT_AS_ARRAY is the only constant : there is no defined constant to explicitly ask for an object as returned value.
See also json_decode. .. index::
json
1.2.1124.1. Suggestions¶
Use the correct second argument of json_decode() : JSON_OBJECT_AS_ARRAY
1.2.1124.2. Specs¶
Short name |
Structures/JsonWithOption |
Rulesets |
|
Exakat since |
1.4.3 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1125. list() May Omit Variables¶
Simply omit any unused variable in a list() call.
list() is the only PHP function that accepts to have omitted arguments. If the following code makes no usage of a listed variable, just omit it.
<?php
// No need for '2', so no assignation
list ($a, , $b) = array(1, 2, 3);
// works with PHP 7.1 short syntax
[$a, , $b] = array(1, 2, 3);
// No need for '2', so no assignation
list ($a, $c, $b) = array(1, 2, 3);
?>
See also list.
1.2.1125.1. Suggestions¶
Remove the unused variables from the list call
When the ignored values are at the beginning or the end of the array, array_slice() may be used to shorten the array.
1.2.1126. Logical Mistakes¶
Avoid logical mistakes within long expressions.
Sometimes, the logic is not what it seems. It is important to check the actual impact of every part of the logical expression. Do not hesitate to make a table with all possible cases. If those cases are too numerous, it may be time to rethink the whole expression.
<?php
// Always true
if ($a != 1 || $a != 2) { }
// $a == 1 is useless
if ($a == 1 || $a != 2) {}
// Always false
if ($a == 1 && $a == 2) {}
// $a != 2 is useless
if ($a == 1 && $a != 2) {}
?>
Based on article from Andrey Karpov Logical Expressions in C/C++. Mistakes Made by Professionals
1.2.1126.1. Suggestions¶
Change the expressions for them to have a real meaning
1.2.1126.2. Specs¶
Short name |
Structures/LogicalMistakes |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Critical |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1127. Lone Blocks¶
Any grouped code without a commanding structure is useless.
Blocks are compulsory when defining a structure, such as a class or a function. They are most often used with flow control instructions, like if then or switch.
Blocks are also valid syntax that group several instructions together, though they have no effect at all, except confuse the reader. Most often, it is a ruin from a previous flow control instruction, whose condition was removed or commented. They should be removed.
<?php
// Lone block
//foreach($a as $b)
{
$b++;
}
?>
1.2.1127.1. Suggestions¶
Remove the useless curly brackets
1.2.1127.2. Specs¶
Short name |
Structures/LoneBlock |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1128. Long Arguments¶
Long arguments should be put in variable, to preserve readability.
When literal arguments are too long, they break the hosting structure by moving the next argument too far on the right. Whenever possible, long arguments should be set in a local variable to keep the readability.
<?php
// Now the call to foo() is easier to read.
$reallyBigNumber = <<<BIGNUMBER
123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
BIGNUMBER
foo($reallyBigNumber, 2, '12345678901234567890123456789012345678901234567890');
// where are the next arguments ?
foo('123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890', 2, '123456789012345678901234567890123456789012345678901234567890');
// This is still difficult to read
foo(<<<BIGNUMBER
123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
BIGNUMBER
, 2, '123456789012345678901234567890123456789012345678901234567890');
?>
Literal strings and heredoc strings, including variables, that are over 50 chars longs are reported here.
1.2.1128.1. Suggestions¶
Put the long arguments in a separate variable, and use the variable in the second expression, reducing its total length
Name |
Default |
Type |
Description |
codeTooLong |
100 |
integer |
Minimum size of a functioncall or a methodcall to be considered too long. |
1.2.1128.2. Specs¶
Short name |
Structures/LongArguments |
Rulesets |
|
Exakat since |
0.9.7 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1129. Too Long A Block¶
The loop is operating on a block that is too long.
This analysis is applied to loops (for, foreach, while, do..while) and if/then/else/elseif structures.
Then length of a block is managed with the longBlock parameter. By default, it is 200 lines, from beginning to the end. Comments are taken into account.
<?php
$i = 0;
do {
// 200 lines of PHP code
++$i;
} while($i < 100);
?>
1.2.1129.1. Suggestions¶
Move the code of the block to an method or a function
Move part of the code of the block to methods or functions
Extract repeated patterns and use them
Name |
Default |
Type |
Description |
longBlock |
200 |
integer |
Size of a block for it to be too long. A block is commanded by a for, foreach, while, do…while, if/then else structure. |
1.2.1129.2. Specs¶
Short name |
Structures/LongBlock |
Rulesets |
|
Exakat since |
2.1.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1130. Mail Usage¶
Report usage of mail from PHP.
The analysis is based on mail() function and various classes used to send mail.
<?php
// The message
$message = Line 1\r\nLine 2\r\nLine 3;
// In case any of our lines are larger than 70 characters, we should use wordwrap()
$message = wordwrap($message, 70, \r\n);
// Send
mail('caffeinated@example.com', 'My Subject', $message);
?>
See also mail.
1.2.1130.1. Specs¶
Short name |
Structures/MailUsage |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1131. Max Level Of Nesting¶
Avoid nesting structures too deep, as it hurts readability.
Nesting structures are : if/then, switch, for, foreach, while, do…while. Ternary operator, try/catch are not considered a nesting structures.
Closures, and more generally, functions definitions are counted separatedly.
This analysis checks for 4 levels of nesting, by default. This may be changed by configuration.
<?php
// 5 levels of indentation
function foo() {
if (1) {
if (2) {
if (3) {
if (4) {
if (5) {
51;
} else {
5;
}
} else {
4;
}
} else {
3;
}
} else {
2;
}
} else {
1;
}
}
// 2 levels of indentation
function foo() {
if (1) {
if (2) {
// 3 levels of indentation
return function () {
if (3) {
if (4) {
if (5) {
51;
} else {
5;
}
} else {
4;
}
} else {
3;
}
}
} else {
2;
}
} else {
1;
}
}
?>
1.2.1131.1. Suggestions¶
Refactor code to avoid nesting
Export some nested blocks to an external method or function
Name |
Default |
Type |
Description |
maxLevel |
4 |
integer |
Maximum level of nesting for control flow structures in one scope. |
1.2.1131.2. Specs¶
Short name |
Structures/MaxLevelOfIdentation |
Rulesets |
|
Exakat since |
1.9.3 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1132. Mbstring Third Arg¶
Some mbstring functions use the third argument for offset, not for encoding.
Those are the following functions :
<?php
// Display BC
echo mb_substr('ABC', 1 , 2, 'UTF8');
// Yields Warning: mb_substr() expects parameter 3 to be int, string given
// Display 0 (aka, substring from 0, for length (int) 'UTF8' => 0)
echo mb_substr('ABC', 1 ,'UTF8');
?>
See also mb_substr() manual pages.
1.2.1132.1. Suggestions¶
Add a third argument
Use the default encoding (aka, omit both third AND fourth argument)
1.2.1132.2. Specs¶
Short name |
Structures/MbstringThirdArg |
Rulesets |
|
Exakat since |
1.9.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1133. Mbstring Unknown Encoding¶
The encoding used is not known to the ext/mbstring extension.
This analysis takes in charge all mbstring encoding and aliases. The full list of supported mbstring encoding is available with mb_list_encodings(). Each encoding alias is available with mb_encoding_aliases().
<?php
// Invalid encoding
$str = mb_strtolower($str, 'utf_8');
// Valid encoding
$str = mb_strtolower($str, 'utf8');
$str = mb_strtolower($str, 'UTF8');
$str = mb_strtolower($str, 'UTF-8');
?>
See also ext/mbstring.
1.2.1133.1. Suggestions¶
Use a valid mbstring encoding
1.2.1133.2. Specs¶
Short name |
Structures/MbstringUnknownEncoding |
Rulesets |
|
Exakat since |
1.9.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1134. mcrypt_create_iv() With Default Values¶
Avoid using mcrypt_create_iv() default values.
mcrypt_create_iv() used to have MCRYPT_DEV_RANDOM as default values, and in PHP 5.6, it now uses MCRYPT_DEV_URANDOM.
<?php
$size = mcrypt_get_iv_size(MCRYPT_CAST_256, MCRYPT_MODE_CFB);
// mcrypt_create_iv is missing the second argument
$iv = mcrypt_create_iv($size);
// Identical to the line below
// $iv = mcrypt_create_iv($size, MCRYPT_DEV_RANDOM);
?>
If the code doesn’t have a second argument, it relies on the default value. It is recommended to set explicitly the value, so has to avoid problems while migrating.
See also mcrypt_create_iv().
1.2.1134.1. Specs¶
Short name |
Structures/McryptcreateivWithoutOption |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
5.6- |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.1135. Merge If Then¶
Two successive if/then into one, by merging the two conditions.
<?php
// two merge conditions
if ($a == 1 && $b == 2) {
// doSomething()
}
// two distinct conditions
// two nesting
if ($a == 1) {
if ($b == 2) {
// doSomething()
}
}
?>
1.2.1135.1. Suggestions¶
Merge the two structures into one
1.2.1135.2. Specs¶
Short name |
Structures/MergeIfThen |
Rulesets |
|
Exakat since |
1.9.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1136. Mismatched Ternary Alternatives¶
A ternary operator should yield the same type on both branches.
Ternary operator applies a condition, and yield two different results. Those results will then be processed by code that expects the same types. It is recommended to match the types on both branches of the ternary operator.
<?php
// $object may end up in a very unstable state
$object = ($type == 'Type') ? new $type() : null;
//same result are provided by both alternative, though process is very different
$result = ($type == 'Addition') ? $a + $b : $a * $b;
//Currently, this is omitted
$a = 1;
$result = empty($condition) ? $a : 'default value';
$result = empty($condition) ? $a : getDefaultValue();
?>
1.2.1136.1. Suggestions¶
Use compatible data type in both branch of the alternative
Turn the ternary into a if/then, with different processing
1.2.1136.2. Specs¶
Short name |
Structures/MismatchedTernary |
Rulesets |
|
Exakat since |
0.12.1 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1137. Missing Cases In Switch¶
It seems that some cases are missing in this switch structure.
When comparing two different switch() structures, it appears that some cases are missing in one of them. The set of cases are almost identical, but one of the values are missing.
Switch() structures using strings as literals are compared in this analysis. When the discrepancy between two lists is below 25%, both switches are reported.
<?php
// This switch operates on a, b, c, d and default
switch($a) {
case 'a': doSomethingA(); break 1;
case 'b': doSomethingB(); break 1;
case 'c': doSomethingC(); break 1;
case 'd': doSomethingD(); break 1;
default: doNothing();
}
// This switch operates on a, b, d and default
switch($o->p) {
case 'a': doSomethingA(); break 1;
case 'b': doSomethingB(); break 1;
case 'd': doSomethingD(); break 1;
default: doNothing();
}
?>
In the example, one may argue that the ‘c’ case is actually handled by the ‘default’ case. Otherwise, business logic may request that omission.
1.2.1137.1. Suggestions¶
Add the missing cases
Add comments to mention that missing cases are processed in the default case
1.2.1137.2. Specs¶
Short name |
Structures/MissingCases |
Rulesets |
|
Exakat since |
0.10.7 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Examples |
|
Available in |
1.2.1138. Maybe Missing New¶
This functioncall looks like a class instantiation that is missing the new keyword.
Any function definition was found for that function, but a class with that name was. New is probably missing.
<?php
// Functioncall
$a = foo();
// Class definition
class foo {}
// Function definition
function foo {}
// Functioncall
$a = BAR;
// Function definition
class bar {}
// Constant definition
const BAR = 1;
?>
1.2.1138.1. Suggestions¶
Add the new
Rename the class to distinguish it from the function
Rename the function to distinguish it from the class
1.2.1138.2. Specs¶
Short name |
Structures/MissingNew |
Rulesets |
|
Exakat since |
1.0.4 |
PHP Version |
All |
Severity |
Critical |
Time To Fix |
Instant (5 mins) |
Precision |
Medium |
Available in |
1.2.1139. Missing Parenthesis¶
Add parenthesis to those expression to prevent bugs.
<?php
// Missing some parenthesis!!
if (!$a instanceof Stdclass) {
print Not\n;
} else {
print Is\n;
}
// Could this addition be actually
$c = -$a + $b;
// This one ?
$c = -($a + $b);
?>
See also Operators Precedence.
1.2.1139.1. Specs¶
Short name |
Structures/MissingParenthesis |
Rulesets |
|
Exakat since |
1.2.6 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.1140. Mixed Concat And Interpolation¶
Mixed usage of concatenation and string interpolation is error prone. It is harder to read, and leads to overlooking the concatenation or the interpolation.
<?php
// Concatenation string
$a = $b . 'c' . $d;
// Interpolation strings
$a = {$b}c{$d}; // regular form
$a = {$b}c$d; // irregular form
// Mixed Concatenation and Interpolation string
$a = {$b}c . $d;
$a = $b . c$d;
$a = $b . c{$d};
// Mixed Concatenation and Interpolation string with constant
$a = {$b}c . CONSTANT;
?>
Fixing this issue has no impact on the output. It makes code less error prone.
There are some situations where using concatenation are compulsory : when using a constant, calling a function, running a complex expression or make use of the escape sequence. You may also consider pushing the storing of such expression in a local variable.
1.2.1140.1. Suggestions¶
Only use one type of variable usage : either interpolation, or concatenation
1.2.1140.2. Specs¶
Short name |
Structures/MixedConcatInterpolation |
Rulesets |
|
Exakat since |
0.11.5 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1141. Modernize Empty With Expression¶
empty() accepts expressions as argument. This feature was added in PHP 5.5.
There is no need to store the expression in a variable before testing, unless it is reused later.
<?php
// PHP 5.5+ empty() usage
if (empty(foo($b . $c))) {
doSomethingWithoutA();
}
// Compatible empty() usage
$a = foo($b . $c);
if (empty($a)) {
doSomethingWithoutA();
}
// $a2 is reused, storage is legit
$a2 = strtolower($b . $c);
if (empty($a2)) {
doSomething();
} else {
echo $a2;
}
?>
See also empty() and empty() supports arbitrary expressions.
1.2.1141.1. Suggestions¶
Avoid the temporary variable, and use directly empty()
1.2.1141.2. Specs¶
Short name |
Structures/ModernEmpty |
Rulesets |
|
Exakat since |
0.8.6 |
PHP Version |
5.5+ |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1142. Multiple Catch¶
Indicates if a try structure have several catch statement.
<?php
// This try has several catch
try {
doSomething();
} catch (RuntimeException $e) {
processRuntimeException();
} catch (OtherException $e) {
processOtherException();
}
?>
1.2.1142.1. Specs¶
Short name |
Structures/MultipleCatch |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1143. Multiples Identical Case¶
Some cases are defined multiple times, but only one will be processed. Check the list of cases, and remove the extra one.
Exakat tries to find the value of the case as much as possible, and ignore any dynamic cases (using variables).
<?php
const A = 1;
case ($x) {
case 1 :
break;
case true: // This is a duplicate of the previous
break;
case 1 + 0: // This is a duplicate of the previous
break;
case 1.0 : // This is a duplicate of the previous
break;
case A : // The A constant is actually 1
break;
case $y : // This is not reported.
break;
default:
}
?>
1.2.1143.1. Suggestions¶
Remove the double case
Change the case to another and rightful value
1.2.1143.2. Specs¶
Short name |
Structures/MultipleDefinedCase |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
ClearPHP |
|
Examples |
|
Available in |
1.2.1144. Multiple Type Variable¶
Avoid using the same variable with different types of data.
It is recommended to use different names for differently typed data, while processing them. This prevents errors where one believe the variable holds the former type, while it has already been cast to the later.
Incrementing variables, with math operations or concatenation, is OK : the content changes, but not the type. And casting the variable without storing it in itself is OK.
<?php
// $x is an array
$x = range('a', 'z');
// $x is now a string
$x = join('', $x);
$c = count($x); // $x is not an array anymore
// $letters is an array
$letters = range('a', 'z');
// $alphabet is a string
$alphabet = join('', $letters);
// Here, $letters is cast by PHP, but the variable is changed.
if ($letters) {
$count = count($letters); // $letters is still an array
}
?>
1.2.1144.1. Suggestions¶
Use a class that accepts one type of argument, and exports another type of argument.
Use different variable for each type of data format : $rows (for array), $list (for implode(‘’, $rows))
Pass the final result as argument to another method, avoiding the temporary variable
1.2.1144.2. Specs¶
Short name |
Structures/MultipleTypeVariable |
Rulesets |
|
Exakat since |
0.12.15 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1145. Multiple Unset()¶
<?php
// One call to unset only
unset($a, $b, $c, $d);
// Too many calls to unset
unset($a);
unset($b);
unset($c);
unset($d);
?>
See also unset.
1.2.1145.1. Suggestions¶
Merge all unset into one call
1.2.1145.2. Specs¶
Short name |
Structures/MultipleUnset |
Rulesets |
|
Exakat since |
1.7.6 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1146. Multiply By One¶
Multiplying by 1 is a fancy type cast.
If it is used to type cast a value to number, then casting (int) or (float) is clearer. This behavior may change with PHP 7.1, which has unified the behavior of all hidden casts.
<?php
// Still the same value than $m, but now cast to integer or float
$m = $m * 1;
// Still the same value than $m, but now cast to integer or float
$n *= 1;
// make typecasting clear, and merge it with the producing call.
$n = (int) $n;
?>
See also Type Juggling
1.2.1146.1. Suggestions¶
Typecast to (int) or (float) for better readability
Skip useless math operation altogether
1.2.1146.2. Specs¶
Short name |
Structures/MultiplyByOne |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
ClearPHP |
|
Examples |
|
Available in |
1.2.1147. Named Regex¶
Captured subpatterns may be named, for easier reference.
From the manual : It is possible to name a subpattern using the syntax (?P<name>pattern). This subpattern will then be indexed in the matches array by its normal numeric position and also by name. PHP 5.2.2 introduced two alternative syntaxes (?<name>pattern) and (?'name'pattern).
Naming subpatterns makes it easier to know what is read from the results of the subpattern : for example, $r['name'] has more meaning than $r[1].
Named subpatterns may also be shifted in the regex without impact on the resulting array.
<?php
$x = 'abc';
preg_match_all('/(?<name>a)/', $x, $r);
print_r($r[1]);
print_r($r['name']);
preg_match("/(?<name>a)(?'sub'b)/", $x, $s);
print $s[2];
print $s['sub'];
?>
See also Subpatterns.
1.2.1147.1. Suggestions¶
Use named regex, and stop using integer-named subpatterns
1.2.1147.2. Specs¶
Short name |
Structures/NamedRegex |
Rulesets |
|
Exakat since |
1.4.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Examples |
|
Available in |
1.2.1148. Negative Power¶
The power operator ** has higher precedence than the sign operators + and -.
This means that -2 ** 2 == -4. It is in fact, -(2 ** 2).
When using negative power, it is clearer to add parenthesis or to use the pow() function, which has no such ambiguity :
<?php
// -2 to the power of 2 (a square)
pow(-2, 2) == 4;
// minus 2 to the power of 2 (a negative square)
-2 ** 2 == -(2 ** 2) == 4;
?>
1.2.1148.1. Suggestions¶
Avoid negative number, as operands of **
Use parenthesis with negative numbers and **
1.2.1148.2. Specs¶
Short name |
Structures/NegativePow |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.1149. Nested Ifthen¶
Three levels of ifthen is too much. The method should be split into smaller functions.
<?php
function foo($a, $b) {
if ($a == 1) {
// Second level, possibly too much already
if ($b == 2) {
}
}
}
function bar($a, $b, $c) {
if ($a == 1) {
// Second level.
if ($b == 2) {
// Third level level.
if ($c == 3) {
// Too much
}
}
}
}
?>
Name |
Default |
Type |
Description |
nestedIfthen |
3 |
integer |
Maximal number of acceptable nesting of if-then structures |
1.2.1149.1. Specs¶
Short name |
Structures/NestedIfthen |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1150. Nested Loops¶
Nested loops happens when a loop (while, do..while, for, foreach), is used inside another loop.
<?php
// Nested loops
foreach($array as $a) {
foreach ($letters as $b) {
// This is performed count($array) * count($letters) times.
doSomething();
}
}
?>
Such structure tends to require a lot of processing, as the size of both loops have to be multiplied to estimate the actual payload. They should be avoided as much as possible. This may no be always possible, though.
Nested loops are worth a check for performances reasons, as they will process a lot of times the same instructions.
1.2.1150.1. Specs¶
Short name |
Structures/NestedLoops |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1151. Nested Ternary¶
Ternary operators should not be nested too deep.
They are a convenient instruction to apply some condition, and avoid a if() structure. It works best when it is simple, like in a one liner.
However, ternary operators tends to make the syntax very difficult to read when they are nested. It is then recommended to use an if() structure, and make the whole code readable.
<?php
// Simple ternary expression
echo ($a == 1 ? $b : $c) ;
// Nested ternary expressions
echo ($a === 1 ? $d === 2 ? $b : $d : $d === 3 ? $e : $c) ;
echo ($a === 1 ? $d === 2 ? $f ===4 ? $g : $h : $d : $d === 3 ? $e : $i === 5 ? $j : $k) ;
//Previous expressions, written as a if / Then expression
if ($a === 1) {
if ($d === 2) {
echo $b;
} else {
echo $d;
}
} else {
if ($d === 3) {
echo $e;
} else {
echo $c;
}
}
if ($a === 1) {
if ($d === 2) {
if ($f === 4) {
echo $g;
} else {
echo $h;
}
} else {
echo $d;
}
} else {
if ($d === 3) {
echo $e;
} else {
if ($i === 5) {
echo $j;
} else {
echo $k;
}
}
}
?>
See also Nested Ternaries are Great.
1.2.1151.1. Suggestions¶
Replace ternaries by if/then structures.
Replace ternaries by a functioncall : this provides more readability, offset the actual code, and gives room for making it different.
1.2.1151.2. Specs¶
Short name |
Structures/NestedTernary |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
ClearPHP |
|
Examples |
|
Available in |
1.2.1152. Always Positive Comparison¶
When comparing them to 0, the following expressions are always true and should be avoided.
<?php
$a = [1, 2, 3];
var_dump(count($a) >= 0);
var_dump(count($a) < 0);
?>
1.2.1152.1. Suggestions¶
Compare count() to non-zero values
Use empty()
1.2.1152.2. Specs¶
Short name |
Structures/NeverNegative |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1153. New Line Style¶
New lines may be written with the sequence n or with the constant PHP_EOL.
When one of those alternatives is used over 90% of the time, it is considered as standard : the remaining are reported.
n are only located when used alone, in n (including the double quotes). When n is used inside a double-quoted string, its replacement with PHP_EOL would be cumbersome : as such, they are ignored by this analyzer.
<?php
// This may be repeated over 10 times
$a = PHP is a great language\n;
$a .= \n;
// This only appears once in the code : this line is reported.
$b = $a.PHP_EOL.$c;
?>
1.2.1153.1. Specs¶
Short name |
Structures/NewLineStyle |
Rulesets |
|
Exakat since |
0.9.8 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1154. Next Month Trap¶
Avoid using +1 month with strtotime().
strtotime() calculates the next month by incrementing the month number. For day number that do not exist from one month to the next, strtotime() fixes them by setting them in the next-next month.
This happens to January, March, May, July, August and October. January is also vulnerable for 29 (not every year), 30 and 31.
Avoid using ‘+1 month’, and rely on ‘first day of next month’ or ‘last day of next month’ to extract the next month’s name.
<?php
// Base date is October 31 => 10/31
// +1 month adds +1 to 10 => 11/31
// Since November 31rst doesn't exists, it is corrected to 12/01.
echo date('F', strtotime('+1 month',mktime(0,0,0,$i,31,2017))).PHP_EOL;
// Base date is October 31 => 10/31
echo date('F', strtotime('first day of next month',mktime(0,0,0,$i,31,2017))).PHP_EOL;
?>
See also It is the 31st again.
1.2.1154.1. Suggestions¶
Review strtotime() usage for month additions
Use datetime() and other classes, not PHP native functions
Use a external library, like carbon, to handle dates
1.2.1154.2. Specs¶
Short name |
Structures/NextMonthTrap |
Rulesets |
|
Exakat since |
1.0.1 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1155. No Append On Source¶
Do not append new elements to an array in a foreach loop. Since PHP 7.0, the array is still used as a source, and will be augmented, and used again.
<?php
// Relying on the initial copy
$a = [1];
$initial = $a;
foreach($initial as $v) {
$a[] = $v + 1;
}
// Keep new results aside
$a = [1];
$tmp = [];
foreach($a as $v) {
$tmp[] = $v + 1;
}
$a = array_merge($a, $tmp);
unset($tmp);
// Example, courtesy of Frederic Bouchery
// This is an infinite loop
$a = [1];
foreach($a as $v) {
$a[] = $v + 1;
}
?>
Thanks to Frederic Bouchery for the reminder.
See also foreach and What will this code return? #PHP.
1.2.1155.1. Suggestions¶
Use a copy of the source, to avoid modifying it during the loop
Store the new values in a separate storage
1.2.1155.2. Specs¶
Short name |
Structures/NoAppendOnSource |
Rulesets |
|
Exakat since |
1.8.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1156. Avoid array_unique()¶
The native function array_unique() is much slower than using other alternatives, such as array_count_values(), array_flip()/array_keys(), or even a foreach() loops.
<?php
// using array_unique()
$uniques = array_unique($someValues);
// When values are strings or integers
$uniques = array_keys(array_count_values($someValues));
$uniques = array_flip(array_flip($someValues))
//even some loops are faster.
$uniques = [];
foreach($someValues as $s) {
if (!in_array($uniques, $s)) {
$uniques[] $s;
}
}
?>
1.2.1156.1. Suggestions¶
Upgrade to PHP 7.2
Use an alternative way to make values unique in an array, using array_count_values(), for example.
See also and array_unique..
1.2.1156.2. Specs¶
Short name |
Structures/NoArrayUnique |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
With PHP 7.2 and older |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Available in |
1.2.1157. Avoid Large Array Assignation¶
Avoid setting large arrays to local variables. This is done every time the function is called.
There are different ways to avoid this : inject the array, build the array once. Using an constant or even a global variable is faster.
The effect on small arrays (less than 10 elements) is not significant. Arrays with 10 elements or more are reported here. The effect is also more important on functions that are called often, or within loops.
<?php
// with constants, for functions
const ARRAY = array(1,2,3,4,5,6,7,8,9,10,11);
function foo() {
$array = ARRAY;
//more code
}
// with class constants, for methods
class x {
const ARRAY = array(1,2,3,4,5,6,7,8,9,10,11);
function foo() {
$array = self::ARRAY;
//more code
}
}
// with properties, for methods
class x {
private $array = array(1,2,3,4,5,6,7,8,9,10,11);
function foo() {
$array = $this->array;
//more code
}
}
// injection, leveraging default values
function foo($array = array(1,2,3,4,5,6,7,8,9,10,11)) {
//more code
}
// local cache with static
function foo() {
static $array;
if ($array === null) {
$array = array(1,2,3,4,5,6,7,8,9,10,11);
}
//more code
}
// Avoid creating the same array all the time in a function
class x {
function foo() {
// assign to non local variable is OK.
// Here, to a property, though it may be better in a __construct or as default values
$this->s = array(1,2,3,4,5,6,7,8,9,10,11);
// This is wasting resources, as it is done each time.
$array = array(1,2,3,4,5,6,7,8,9,10,11);
}
}
?>
1.2.1157.1. Suggestions¶
Make the literal a global constant or a class constant
Make the literal an argument, so it is injected
Make the literal an property, with it as default value
1.2.1157.2. Specs¶
Short name |
Structures/NoAssignationInFunction |
Rulesets |
|
Exakat since |
0.9.7 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1158. Don’t Change Incomings¶
<?php
// filtering and keeping the incoming value.
$_DATA'id'] = (int) $_GET['id'];
// filtering and changing the incoming value.
$_GET['id'] = strtolower($_GET['id']);
?>
It is recommended to put the modified values in another variable, and keep the original one intact.
1.2.1158.1. Specs¶
Short name |
Structures/NoChangeIncomingVariables |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1159. No Choice¶
A conditional structure is being used, but both alternatives are the same, leading to the illusion of choice.
Either the condition is useless, and may be removed, or the alternatives need to be distinguished.
<?php
if ($condition == 2) {
doSomething();
} else {
doSomething();
}
$condition == 2 ? doSomething() : doSomething();
?>
1.2.1159.1. Suggestions¶
Remove the conditional, and call the expression directly
Replace one of the alternative with a distinct call
Remove the whole conditional : it may end up being useless
1.2.1159.2. Specs¶
Short name |
Structures/NoChoice |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1160. No Direct Access¶
This expression protects files against direct access. It will kill the process if it realizes this is not supposed to be directly accessed.
Those expressions are used in applications and framework, to prevent direct access to definition files.
<?php
// CONSTANT_EXEC is defined in the main file of the application
defined('CONSTANT_EXEC') or die('Access not allowed'); : Constant used!
?>
1.2.1160.1. Specs¶
Short name |
Structures/NoDirectAccess |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1161. No Direct Usage¶
The results of the following functions shouldn’t be used directly, but checked first.
For example, glob() returns an array, unless some error happens, in which case it returns a boolean (false). In such case, however rare it is, plugging glob() directly in a foreach() loops will yield errors.
<?php
// Used without check :
foreach(glob('.') as $file) { /* do Something */ }.
// Used without check :
$files = glob('.');
if (!is_array($files)) {
foreach($files as $file) { /* do Something */ }.
}
?>
1.2.1161.1. Suggestions¶
Check the return of the function before using it, in particular for false, or array().
1.2.1161.2. Specs¶
Short name |
Structures/NoDirectUsage |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Examples |
|
Available in |
1.2.1162. No Empty Regex¶
PHP regex don’t accept empty regex, nor regex with alphanumeric delimiter.
Most of those errors happen at execution time, when the regex is build dynamically, but still may end empty. At compile time, such error are made when the code is not tested before commit.
<?php
// No empty regex
preg_match('', $string, $r);
// Delimiter must be non-alphanumerical
preg_replace('1abc1', $string, $r);
// Delimiter must be non-alphanumerical
preg_replace('1'.$regex.'1', $string, $r);
?>
See also PCRE and Delimiters.
1.2.1162.1. Suggestions¶
Fix the regex by adding regex delimiters
1.2.1162.2. Specs¶
Short name |
Structures/NoEmptyRegex |
Rulesets |
|
Exakat since |
0.11.1 |
PHP Version |
All |
Severity |
Critical |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1163. No get_class() With Null¶
It is not possible to pass explicitly null to get_class() to get the current’s class name. Since PHP 7.2, one must call get_class() without arguments to achieve that result.
<?php
class A {
public function f() {
// Gets the classname
$classname = get_class();
// Gets the classname and a warning
$classname = get_class(null);
}
}
$a = new A();
$a->f('get_class');
?>
1.2.1163.1. Specs¶
Short name |
Structures/NoGetClassNull |
Rulesets |
Analyze, CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, CompatibilityPHP70, CompatibilityPHP71, CompatibilityPHP72, All |
Exakat since |
1.0.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.1164. No Hardcoded Hash¶
Hash should never be hardcoded.
Hashes may be MD5, SHA1, SHA512, Bcrypt or any other. Such values must be easily changed, for security reasons, and the source code is not the safest place to hide it.
<?php
// Those strings may be sha512 hashes.
// it is recomemdned to check if they are static or should be put into configuration
$init512 = array( // initial values for SHA512
'6a09e667f3bcc908', 'bb67ae8584caa73b', '3c6ef372fe94f82b', 'a54ff53a5f1d36f1',
);
// strings which are obvious conversion are ignored
$decimal = intval('87878877', 12);
?>
See also Salted Password Hashing - Doing it Right and Hash-Buster.
1.2.1164.1. Suggestions¶
Put any hardcoded hash in a configuration file, a database or a environment variable. An external source.
1.2.1164.2. Specs¶
Short name |
Structures/NoHardcodedHash |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Critical |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Examples |
|
Available in |
1.2.1165. No Hardcoded Ip¶
Do not leave hard coded IP in your code.
It is recommended to move such configuration in external files or databases, for each update. This may also come handy when testing.
<?php
// This IPv4 is hardcoded.
$ip = '183.207.224.50';
// This IPv6 is hardcoded.
$ip = '2001:0db8:85a3:0000:0000:8a2e:0370:7334';
// This looks like an IP
$thisIsNotAnIP = '213.187.99.50';
$thisIsNotAnIP = '2133:1387:9393:5330';
?>
127.0.0.1, \:\:1 and \:\:0 are omitted, and not considered as a violation.
See also Use of Hardcoded IPv4 Addresses and Never hard code sensitive information.
1.2.1165.1. Suggestions¶
Move the hardcoded IP to an external source : environment variable, configuration file, database.
Remove the hardcoded IP and ask for it at execution.
Use a literal value for default messages in form.
1.2.1165.2. Specs¶
Short name |
Structures/NoHardcodedIp |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Examples |
|
Available in |
1.2.1166. No Hardcoded Path¶
It is not recommended to use hardcoded literals when designating files. Full paths are usually tied to one file system organization. As soon as the organisation changes or must be adapted to any external constraint, the path is not valid anymore.
Either use __FILE__ and __DIR__ to make the path relative to the current file; use a DOC_ROOT as a configuration constant that will allow the moving of the script to another folder; finally functions like sys_get_temp_dir() produce a viable temporary folder.
Relative paths are relative to the current execution directory, and not the current file. This means they may differ depending on the location of the start of the application, and are sensitive to chdir() and chroot() usage.
<?php
// This depends on the current executed script
file_get_contents('token.txt');
// Exotic protocols are ignored
file_get_contents('jackalope://file.txt');
// Some protocols are ignored : http, https, ftp, ssh2, php (with memory)
file_get_contents('http://www.php.net/');
file_get_contents('php://memory/');
// glob() with special chars * and ? are not reported
glob('./*/foo/bar?.txt');
// glob() without special chars * and ? are reported
glob('/foo/bar/');
?>
1.2.1166.1. Suggestions¶
Add __DIR__ before the path to make it relative to the current file
Add a configured prefix before the path to point to any file in the system
Use sys_get_temp_dir() for temporary data
Use
include_pathargument function, such as fie_get_contents(), to have the file located in configurable directories.
1.2.1166.2. Specs¶
Short name |
Structures/NoHardcodedPath |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
ClearPHP |
|
Examples |
|
Available in |
1.2.1167. No Hardcoded Port¶
When connecting to a remove server, port is an important information. It is recommended to make this configurable (with constant or configuration), to as to be able to change this value without changing the code.
<?php
// Both configurable IP and hostname
$connection = ssh2_connect($_ENV['SSH_HOST'], $_ENV['SSH_PORT'], $methods, $callbacks);
// Both hardcoded IP and hostname
$connection = ssh2_connect('shell.example.com', 22, $methods, $callbacks);
if (!$connection) die('Connection failed');
?>
1.2.1167.1. Suggestions¶
Move the port to a configuration file, an environment variable
1.2.1167.2. Specs¶
Short name |
Structures/NoHardcodedPort |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1168. No isset() With empty()¶
From the manual : No warning is generated if the variable does not exist. That means `empty() <https://www.php.net/empty>`_ is essentially the concise equivalent to !`isset( <https://www.www.php.net/isset>`_$var) || $var == false. The main difference is that isset() only works with variables, while empty() works with other structures, such as constants.
<?php
// Enough validation
if (!empty($a)) {
doSomething();
}
// Too many tests
if (isset($a) && !empty($a)) {
doSomething();
}
?>
See also Isset <http://www.php.net/`isset>`_ and empty.
1.2.1168.1. Suggestions¶
Only use isset(), just drop the empty()
Only use empty(), just drop the empty()
Use a null value, so the variable is always set
1.2.1168.2. Specs¶
Short name |
Structures/NoIssetWithEmpty |
Rulesets |
|
Exakat since |
0.8.7 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1169. No Need For Else¶
<?php
function foo() {
// Else may be in the main sequence.
if ($a1) {
return $a1;
} else {
$a++;
}
// Same as above, but negate the condition : if (!$a2) { return $a2; }
if ($a2) {
$a++;
} else {
return $a2;
}
// This is OK
if ($a3) {
return;
}
// This has no break
if ($a4) {
$a++;
} else {
$b++;
}
// This has no else
if ($a5) {
$a++;
}
}
?>
See also Object Calisthenics, rule # 2.
1.2.1169.1. Suggestions¶
Remove else block, but keep the code
1.2.1169.2. Specs¶
Short name |
Structures/NoNeedForElse |
Rulesets |
|
Exakat since |
0.10.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1170. No Need For Triple Equal¶
There is no need for the identity comparison when the methods returns the proper type.
<?php
// foo() returns a string.
if ('a' === foo()) {
// doSomething()
}
function foo() : string {
return 'a';
}
?>
1.2.1170.1. Specs¶
Short name |
Structures/NoNeedForTriple |
Rulesets |
|
Exakat since |
2.1.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1171. No Need For get_class()¶
There is no need to call get_class() to build a static call. The argument of get_class() may be used directly.
<?php
//
$a->b::$c
// This is too much code
get_class($a->b)::$c
?>
See also Scope Resolution Operator (::).
1.2.1171.1. Suggestions¶
Use get_called_class(), which may carry different class names
Use self, static or parent keywords, if you are already in the current class
Use the argument of get_class() directly
1.2.1171.2. Specs¶
Short name |
Structures/NoNeedGetClass |
Rulesets |
|
Exakat since |
1.8.1 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1172. No Object As Index¶
PHP accepts objects as index, though it will report various error messages when this happens.
<?php
$s = 'Hello';
$o = new stdClass();
try {
$s[$o] = 'A';
} catch (\Throwable $e) {
echo $e->getMessage(), \n;
//Cannot access offset of type stdClass on string
}
?>
Thanks to George Peter Banyard for the inspiration.
See also ` https://twitter.com/Girgias/status/1405519800575553540`_
1.2.1172.1. Suggestions¶
Filter values being used as index
Filter values being used as array
1.2.1172.2. Specs¶
Short name |
Structures/NoObjectAsIndex |
Rulesets |
|
Exakat since |
2.2.2 |
PHP Version |
With PHP 8.1 and older |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Medium |
Available in |
1.2.1173. No Parenthesis For Language Construct¶
Some PHP language constructs, such are
include,require,include_once,require_once,echodon’t need parenthesis. They accept parenthesis, but it is may lead to strange situations.
<?php
// This is an attempt to load 'foo.inc', or kill the script
include('foo.inc') or die();
// in fact, this is read by PHP as : include 1
// include 'foo.inc' or die();
?>
It it better to avoid using parenthesis with echo, print, return, throw, yield, yield from, include, require, include_once, require_once.
See also include.
1.2.1173.1. Suggestions¶
Remove parenthesis
1.2.1174. No Reference On Left Side¶
Do not use references as the right element in an assignation.
<?php
$b = 2;
$c = 3;
$a = &$b + $c;
// $a === 2 === $b;
$a = $b + $c;
// $a === 5
?>
This is the case for most situations : addition, multiplication, bitshift, logical, power, concatenation. Note that PHP won’t compile the code if the operator is a short operator (+=, .=, etc.), nor if the & is on the right side of the operator. See also References Explained and Operator Precedence.
1.2.1174.1. Specs¶
Short name |
Structures/NoReferenceOnLeft |
Rulesets |
|
Exakat since |
0.11.5 |
PHP Version |
All |
Severity |
Critical |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Available in |
1.2.1175. No Return Or Throw In Finally¶
Avoid using return and throw in a finally block. Both command will interrupt the processing of the try catch block, and any exception that was emitted will not be processed. This leads to unprocessed exceptions, leaving the application in an unstable state.
Note that PHP prevents the usage of goto, break and continue within the finally block at linting phase. This is categorized as a Security problem.
<?php
function foo() {
try {
// Exception is thrown here
throw new \Exception();
} catch (Exception $e) {
// This is executed AFTER finally
return 'Exception';
} finally {
// This is executed BEFORE catch
return 'Finally';
}
}
}
// Displays 'Finally'. No exception
echo foo();
function bar() {
try {
// Exception is thrown here
throw new \Exception();
} catch (Exception $e) {
// Process the exception.
return 'Exception';
} finally {
// clean the current situation
// Keep running the current function
}
return 'Finally';
}
}
// Displays 'Exception', with processed Exception
echo bar();
?>
See also Return Inside Finally Block.
1.2.1175.1. Suggestions¶
Move the return right after the try/catch/finally call
1.2.1175.2. Specs¶
Short name |
Structures/NoReturnInFinally |
Rulesets |
|
Exakat since |
0.12.1 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1176. Avoid Substr() One¶
Use array notation
$string[$position]to reach a single byte in a string.
There are two ways to access a byte in a string : substr() and $v[$pos].
The second style is more readable. It may be up to four times faster, though it is a micro-optimization. It is recommended to use it.
PHP 7.1 also introduces the support of negative offsets as string index : negative offset are also reported.
<?php
$string = 'ab人cde';
echo substr($string, $pos, 1);
echo $string[$pos];
echo mb_substr($string, $pos, 1);
// when $pos = 1
// displays bbb
// when $pos = 2
// displays ??人
?>
Beware that substr() and $v[$pos] are similar, while mb_substr() is not. The first function works on bytes, while the latter works on characters.
1.2.1176.1. Suggestions¶
Replace substr() with the array notations for strings.
Replace substr() with a call to mb_substr().
1.2.1176.2. Specs¶
Short name |
Structures/NoSubstrOne |
Rulesets |
Analyze, CE, CI-checks, CompatibilityPHP71, Performances, Suggestions, Top10, All |
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1177. Variable Is Not A Condition¶
Using the raw variable as a condition blurs the difference between an undefined variable and an empty value. By using an explicit comparison or validation function, it is easier to understand what the variable stands for.
<?php
if (isset($error)) {
echo 'Found one error : '.$error!;
}
//
if ($errors) {
print count($errors).' errors found : '.join('', $errors).PHP_EOL;
echo 'Not found';
}
?>
Thanks to the PMB team for the inspiration.
1.2.1177.1. Suggestions¶
Make the validation explicit, by using a comparison operator, or one of the validation function.
1.2.1177.2. Specs¶
Short name |
Structures/NoVariableIsACondition |
Rulesets |
|
Exakat since |
1.6.5 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1178. Non Breakable Space In Names¶
PHP allows non-breakable spaces in structures names, such as class, interfaces, traits, and variables.
This may be a nice trick to make names more readable outside code context, like long-named methods for tests.
<?php
class class with non breakable spaces {}
class ClassWithoutNonBreakableSpaces {}
?>
See also the original post by Matthieu Napoli : Using non-breakable spaces in test method names and PHP Variable Names.
1.2.1178.1. Specs¶
Short name |
Structures/NonBreakableSpaceInNames |
Rulesets |
|
Exakat since |
0.12.0 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1179. @ Operator¶
@ is the ‘no scream’ operator : it suppresses error output.
<?php
// Set x with incoming value, or else null.
$x = @$_GET['x'];
?>
This operator is actually very slow : it will process the error all the way up, and finally decide not to display it. It is often faster to check the conditions first, then run the method without @.
You may also set display_error to 0 in the php.ini : this will avoid user’s error display, but will keep the error in the PHP logs, for later processing.
The only situation where @ is useful is when a native PHP function displays errors messages when error happens and there is no way to check it from the code.
This is the case with fopen(), stream_socket_server(), token_get_all().
See also Error Control Operators and Five reasons why the shut-op operator should be avoided.
1.2.1179.1. Suggestions¶
Remove the @ operator by default
Name |
Default |
Type |
Description |
authorizedFunctions |
noscream_functions.json |
data |
Functions that are authorized to sports a @. |
1.2.1179.2. Specs¶
Short name |
Structures/Noscream |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
ClearPHP |
|
Examples |
|
Available in |
1.2.1180. Not Equal Is Not !==¶
Not and Equal operators, used separately, don’t amount to the different operator
!==.
!$a == $b first turns $a``into the opposite boolean, then compares this boolean value to ``$b. On the other hand, $a !== $b compares the two variables for type and value, and returns a boolean.
<?php
if ($string != 'abc') {
// doSomething()
}
// Here, string will be an boolean, leading
if (!$string == 'abc') {
// doSomething()
}
// operator priority may be confusing
if (!$object instanceof OneClass) {
// doSomething()
}
?>
Note that the instanceof operator may be use with this syntax, due to operator precedence.
See also Operator Precedence.
1.2.1180.1. Suggestions¶
Use the != or !==
Use parenthesis
1.2.1180.2. Specs¶
Short name |
Structures/NotEqual |
Rulesets |
|
Exakat since |
2.0.6 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1181. Not Not¶
Double not makes a boolean, not a
true.
This is a wrong casting to boolean. PHP supports (boolean) to do the same, faster and cleaner.
<?php
// Explicit code
$b = (boolean) $x;
$b = (bool) $x;
// Wrong type casting
$b = !!$x;
?>
See also Logical Operators and Type Juggling.
1.2.1181.1. Suggestions¶
Use
(bool)casting operator for thatDon’t typecast, and let PHP handle it. This works in situations where the boolean is immediately used.
1.2.1181.2. Specs¶
Short name |
Structures/NotNot |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
ClearPHP |
|
Examples |
|
Available in |
1.2.1182. Not Or Tilde¶
There are two NOT operator in PHP :
!and~. The first is a logical operator, and returns a boolean. The second is a bit-wise operator, and flips each bit.
Although they are distinct operations, there are situations where they provide the same results. In particular, when processing booleans.
Yet, ! and ~ are not the same. ~ has a higher priority, and will not yield to instanceof, while ! does.
The analyzed code has less than 10% of one of them : for consistency reasons, it is recommended to make them all the same.
<?php
// be consistent
if (!$condition) {
doSomething();
}
if (~$condition) {
doSomething();
}
?>
- See also Bitwise Operators,
1.2.1182.1. Suggestions¶
Be consistent
1.2.1182.2. Specs¶
Short name |
Structures/NotOrNot |
Rulesets |
|
Exakat since |
1.8.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1183. Objects Don’t Need References¶
There is no need to create references for objects, as those are always passed by reference when used as arguments.
Note that when the argument is assigned another value, including another object, then the reference is needed : PHP forgets about reference when they are replaced.
<?php
$object = new stdClass();
$object->name = 'a';
foo($object);
print $object->name; // Name is 'b'
// No need to make $o a reference
function foo(&$o) {
$o->name = 'b';
}
// $o is assigned inside the function : it must be called with a &, or the object won't make it out of the foo3 scope
function foo3(&$o) {
$o = new stdClass;
}
$array = array($object);
foreach($array as &$o) { // No need to make this a reference
$o->name = 'c';
}
?>
1.2.1183.1. Suggestions¶
Remove the reference
Assign the argument with a new value
See also and Passing by reference.
1.2.1183.2. Specs¶
Short name |
Structures/ObjectReferences |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
ClearPHP |
|
Examples |
|
Available in |
1.2.1184. include_once() Usage¶
include_once() and require_once() functions should be avoided for performances reasons.
<?php
// Including a library.
include 'lib/helpers.inc';
// Including a library, and avoiding double inclusion
include_once 'lib/helpers.inc';
?>
Try using autoload for loading classes, or use include() or require() and make it possible to include several times the same file without errors.
1.2.1184.1. Suggestions¶
Avoid using include_once() whenever possible
Use autoload() to load classes, and avoid loading them with include
1.2.1184.2. Specs¶
Short name |
Structures/OnceUsage |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1185. One Dot Or Object Operator Per Line¶
Rule #4 of Object Calisthenics : Only one -> or . per line.
<?php
// Those should be on different lines for readability
$a->foo()->bar()->getFinal();
$a->foo()
->bar()
->getFinal();
// Those should be on different lines for readability
$concatenation = 'a' . 'b' . $c . 'd';
$concatenation = 'a' .
'b' .
$c .
'd';
?>
This analysis will also catch the following cases :
<?php
// set of multiples (concatenations or properties or methodcalls)
foo('a' . 'b', 'c'. 'd');
foo('a' . 'b', $c->d);
?>
When kept, simple, this rule has some edge cases which are left to the reader.
<?php
$a = 'a' . 'b'
.
'c' . 'd';
$c = $f->g('e' . 'f');
$e = A::B::D;
?>
1.2.1185.1. Specs¶
Short name |
Structures/OneDotOrObjectOperatorPerLine |
Rulesets |
|
Exakat since |
0.8.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1186. One Expression Brackets Consistency¶
Brackets around one-line expressions are not consistent.
PHP makes bracket optional when a control structure pilot only one expression. Both are semantically identical.
This analysis reports code that uses brackets while the vast majority of other expressions uses none. Or the contrary.
<?php
// One expression with brackets
for($i = 0; $i < 10; $i++) { $c++; }
// One expression without bracket
for($i2 = 0; $i2 < 10; $i2++) $c++;
?>
Another analysis, [Structures/Bracketless], reports the absence of brackets as an error.
1.2.1186.1. Specs¶
Short name |
Structures/OneExpressionBracketsConsistency |
Rulesets |
|
Exakat since |
0.9.5 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1187. One If Is Sufficient¶
Nested conditions may be written another way, and reduce the amount of code.
Nested conditions are equivalent to a && condition. As such, they may be switched. When one of the condition has no explicit else, then it is lighter to write it as the first condition. This way, it is written once, and not repeated.
<?php
// Less conditions are written here.
if($b == 2) {
if($a == 1) {
++$c;
}
else {
++$d;
}
}
// ($b == 2) is double here
if($a == 1) {
if($b == 2) {
++$c;
}
}
else {
if($b == 2) {
++$d;
}
}
?>
1.2.1187.1. Suggestions¶
Switch the if…then conditions, to reduce the amount of conditions to read.
1.2.1187.2. Specs¶
Short name |
Structures/OneIfIsSufficient |
Rulesets |
|
Exakat since |
1.2.6 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1188. More Than One Level Of Indentation¶
According to PHP Object Calisthenics, one level of indentation is sufficient.
It helps to abide by the Single Responsibility rule and increase reuse.
<?php
class foo {
function multipleLevels($array) {
$return = array();
foreach($array as $b) {
// This is a second level of indentation
if ($this->check($b)) { continue; }
$return[] = $b;
}
return $return;
}
function oneLevel($array) {
$return = array_filter($array, array($this, 'check'));
return $return;
}
}
?>
1.2.1188.1. Specs¶
Short name |
Structures/OneLevelOfIndentation |
Rulesets |
|
Exakat since |
0.8.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1189. Several Instructions On The Same Line¶
Usually, instructions do not share their line : one instruction, one line.
This is good for readability, and help at understanding the code. This is especially important when fast-reading the code to find some special situation, where such double-meaning line way have an impact.
<?php
switch ($x) {
// Is it a fallthrough or not ?
case 1:
doSomething(); break;
// Easily spotted break.
case 1:
doSomethingElse();
break;
default :
doDefault();
break;
}
?>
See also Object Calisthenics, rule # 5.
1.2.1189.1. Suggestions¶
Add new lines, so that one expression is on one line
1.2.1189.2. Specs¶
Short name |
Structures/OneLineTwoInstructions |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1190. Only First Byte¶
When assigning a char to a string with an array notation, only the first byte is used.
<?php
$str = 'xy';
// first letter is now a
$str[0] = 'a';
// second letter is now b, c is ignored
$str[1] = 'bc';
?>
See also String access and modification by character.
1.2.1190.1. Suggestions¶
Remove extra bytes when assigning to a string
Use concatenation
Use strpos() and substr() functions
Use explode(), implode() functions and array manipulations
1.2.1190.2. Specs¶
Short name |
Structures/OnlyFirstByte |
Rulesets |
|
Exakat since |
2.2.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Medium |
Available in |
1.2.1191. Only Variable Returned By Reference¶
Function can’t return literals by reference.
When a function returns a reference, it is only possible to return variables, properties or static properties.
Anything else, like literals or static expressions, yield a warning at execution time.
<?php
// Can't return a literal number
function &foo() {
return 3 + rand();
}
// bar must return values that are stored in a
function &bar() {
$a = 3 + rand();
return $a;
}
?>
1.2.1191.1. Specs¶
Short name |
Structures/OnlyVariableReturnedByReference |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1192. openssl_random_pseudo_byte() Second Argument¶
openssl_random_pseudo_byte() uses exceptions to signal an error. Since PHP 7.4, there is no need to use the second argument.
On the other hand, it is important to catch the exception that openssl_random_pseudo_byte() may emit.
<?php
// PHP 7.4 way to check on random number generation
try {
$bytes = openssl_random_pseudo_bytes($i);
} catch(\Exception $e) {
die(Error while loading random number);
}
// Old way to check on random number generation
$bytes = openssl_random_pseudo_bytes($i, $cstrong);
if ($cstrong === false) {
die(Error while loading random number);
}
?>
See also openssl_random_pseudo_byte and PHP RFC: Improve `openssl_random_pseudo_bytes() <https://wiki.php.net/rfc/improve-openssl-random-pseudo-bytes>`_.
1.2.1192.1. Suggestions¶
Skip the second argument, add a try/catch around the call to openssl_random_pseudo_bytes()
1.2.1192.2. Specs¶
Short name |
Structures/OpensslRandomPseudoByteSecondArg |
Rulesets |
|
Exakat since |
1.9.3 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1193. Or Die¶
Classic old style failed error management.
<?php
// In case the connexion fails, this kills the current script
mysql_connect('localhost', $user, $pass) or die();
?>
Interrupting a script will leave the application with a blank page, will make your life miserable for testing. Just don’t do that.
See also pg_last_error or PDO::exec.
1.2.1193.1. Suggestions¶
Throw an exception
Trigger an error with trigger_error()
Use your own error mechanism
1.2.1193.2. Specs¶
Short name |
Structures/OrDie |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
ClearPHP |
|
Examples |
|
Available in |
1.2.1194. PHP7 Dirname¶
<?php
$path = '/a/b/c/d/e/f';
// PHP 7 syntax
$threeFoldersUp = dirname($path, 3);
// PHP 5 syntax
$threeFoldersUp = dirname(dirname(dirname($path)));
?>
1.2.1194.2. Specs¶
Short name |
Structures/PHP7Dirname |
Rulesets |
CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, php-cs-fixable, Suggestions, All |
Exakat since |
0.8.4 |
PHP Version |
With PHP 7.0 and more recent |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1195. Phpinfo¶
phpinfo() is a great function to learn about the current configuration of the server.
<?php
if (DEBUG) {
phpinfo();
}
?>
If left in the production code, it may lead to a critical leak, as any attacker gaining access to this data will know a lot about the server configuration.
It is advised to never leave that kind of instruction in a production code.
phpinfo() may be necessary to access some specific configuration of the server : for example, Apache module list are only available via phpinfo(), and apache_get(), when they are loaded.
1.2.1195.1. Suggestions¶
Remove all usage of phpinfo()
Add one or more constant to fine-tune the phpinfo(), and limit the amount of displayed information
Replace phpinfo() with a more adapted method : get_loaded_extensions() to access the list of loaded extensions
See also and .
1.2.1195.2. Specs¶
Short name |
Structures/PhpinfoUsage |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1196. No Plus One¶
Incrementing a variable should be done with the ++ or – operators. Any other way, may be avoided.
<?php
// Best way to increment
++$x; --$y;
// Second best way to increment, if the current value is needed :
echo $x++, $y--;
// Good but slow
$x += 1;
$x -= -1;
$y += -1;
$y -= 1;
// even slower
$x = $x + 1;
$y = $y - 1;
?>
This is a micro optimisation.
1.2.1196.1. Specs¶
Short name |
Structures/PlusEgalOne |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1197. Possible Increment¶
This expression looks like a typo : a missing + would change the behavior.
The same pattern is not reported with -, as it is legit expression. + sign is usually understated, rather than explicit.
<?php
// could it be a ++$b ?
$a = +$b;
?>
- See also and
.
1.2.1197.1. Suggestions¶
Drop the whole assignation
Complete the addition with another value : $a = 1 + $b
Make this a ++ operator : ++$b
Make this a negative operator : -$b
Make the casting explicit : (int) $b
See also Incrementing/Decrementing Operators and Arithmetic Operators.
1.2.1197.2. Specs¶
Short name |
Structures/PossibleIncrement |
Rulesets |
|
Exakat since |
1.2.1 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1198. Possible Infinite Loop¶
Loops on files that can’t be open results in infinite loop.
fgets(), and functions like fgetss(), fgetcsv(), fread(), return false when they finish reading, or can’t access the file.
In case the file is not accessible, comparing the result of the reading to something that is falsy, leads to a permanent valid condition. The execution will only finish when the max_execution_time is reached.
<?php
$file = fopen('/path/to/file.txt', 'r');
// when fopen() fails, the next loops is infinite
// fgets() will always return false, and while will always be true.
while($line = fgets($file) != 'a') {
doSomething();
}
?>
It is recommended to check the file resources when they are opened, and always use === or !== to compare readings. feof() is also a reliable function here.
1.2.1198.1. Specs¶
Short name |
Structures/PossibleInfiniteLoop |
Rulesets |
|
Exakat since |
1.1.5 |
PHP Version |
All |
Severity |
Critical |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1199. Print And Die¶
Die() <https://www.php.net/`die>`_ also prints.
When stopping a script with die() <https://www.php.net/`die>`_, it is possible to provide a message as first argument, that will be displayed at execution. There is no need to make a specific call to print or echo.
<?php
// die may do both print and die.
echo 'Error message';
die();
// exit may do both print and die.
print 'Error message';
exit;
// exit cannot print integers only : they will be used as status report to the system.
print 'Error message';
exit 1;
?>
1.2.1199.1. Specs¶
Short name |
Structures/PrintAndDie |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.1200. Avoid Parenthesis¶
Avoid Parenthesis for language construct. Languages constructs are a few PHP native elements, that looks like functions but are not.
Among other distinction, those elements cannot be directly used as variable function call, and they may be used with or without parenthesis.
<?php
// normal usage of include
include 'file.php';
// This looks like a function and is not
include('file2.php');
?>
The usage of parenthesis actually give some feeling of comfort, it won’t prevent PHP from combining those argument with any later operators, leading to unexpected results.
Even if most of the time, usage of parenthesis is legit, it is recommended to avoid them.
1.2.1200.1. Specs¶
Short name |
Structures/PrintWithoutParenthesis |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1201. Printf Number Of Arguments¶
Extra arguments are ignored, and are dead code as such. Missing arguments are reported with a warning, and nothing is displayed.
Omitted arguments produce an error.
<?php
// not enough
printf(' a %s ', $a1);
// OK
printf(' a %s ', $a1, $a2);
// too many
printf(' a %s ', $a1, $a2, $a3);
// not enough
sprintf(' a %s ', $a1);
// OK
\sprintf(' a %s ', $a1, $a2);
// too many
sprintf(' a %s ', $a1, $a2, $a3);
?>
1.2.1201.1. Suggestions¶
Sync the number of argument with the format command
1.2.1201.2. Specs¶
Short name |
Structures/PrintfArguments |
Rulesets |
|
Exakat since |
1.0.1 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
Medium |
Examples |
|
Available in |
1.2.1202. Property Variable Confusion¶
Within a class, there is both a property and variables bearing the same name.
<?php
class Object {
private $x;
function SetData( ) {
$this->x = $x + 2;
}
}
?>
The property and the variable may easily be confused one for another and lead to a bug.
Sometimes, when the property is going to be replaced by the incoming argument, or data based on that argument, this naming schema is made on purpose, indicating that the current argument will eventually end up in the property. When the argument has the same name as the property, no warning is reported.
1.2.1202.1. Suggestions¶
Use different names for the properties and variables
Adopt and apply a naming convention for variables and properties.
1.2.1202.2. Specs¶
Short name |
Structures/PropertyVariableConfusion |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Examples |
|
Available in |
1.2.1203. Queries In Loops¶
Avoid querying databases in a loop.
Querying an external database in a loop usually leads to performances problems. This is also called the ‘n + 1 problem’.
This problem applies also to prepared statement : when such statement are called in a loop, they are slower than one-time large queries.
It is recommended to reduce the number of queries by making one query, and dispatching the results afterwards. This is true with SQL databases, graph queries, LDAP queries, etc.
<?php
// Typical N = 1 problem : there will be as many queries as there are elements in $array
$ids = array(1,2,3,5,6,10);
$db = new SQLite3('mysqlitedb.db');
// all the IDS are merged into the query at once
$results = $db->query('SELECT bar FROM foo WHERE id in ('.implode(',', $id).')');
while ($row = $results->fetchArray()) {
var_dump($row);
}
// Typical N = 1 problem : there will be as many queries as there are elements in $array
$ids = array(1,2,3,5,6,10);
$db = new SQLite3('mysqlitedb.db');
foreach($ids as $id) {
$results = $db->query('SELECT bar FROM foo WHERE id = '.$id);
while ($row = $results->fetchArray()) {
var_dump($row);
}
}
?>
This optimisation is not always possible : for example, some SQL queries may not be prepared, like DROP TABLE or DESC. UPDATE commands often update one row at a time, and grouping such queries may be counter-productive or unsafe.
1.2.1203.1. Suggestions¶
Batch calls by using WHERE clauses and applying the same operation to all similar data
Use native commands to avoid double query : REPLACE instead of SELECT-(UPDATE/INSERT), or UPSERT, for example
1.2.1203.2. Specs¶
Short name |
Structures/QueriesInLoop |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Examples |
|
Available in |
1.2.1204. Random Without Try¶
random_int() and random_bytes() require a try/catch structure around them.
random_int() and random_bytes() emit Exceptions if they meet a problem. This way, failure can’t be mistaken with returning an empty value, which leads to lower security.
<?php
try {
$salt = random_bytes($length);
} catch (TypeError $e) {
// Error while reading the provided parameter
} catch (Exception $e) {
// Insufficient random data generated
} catch (Error $e) {
// Error with the provided parameter : <= 0
}
?>
Since PHP 7.4, openssl_random_pseudo_bytes() has adopted the same behavior. It is included in this analysis : check your PHP version for actual application.
1.2.1204.1. Suggestions¶
Add a try/catch structure around calls to random_int() and random_bytes().
See also and .
1.2.1204.2. Specs¶
Short name |
Structures/RandomWithoutTry |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
With PHP 7.0 and more recent |
Severity |
Critical |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Available in |
1.2.1205. Regex Delimiter¶
PCRE regular expressions may use a variety of delimiters.
There seems to be a standard delimiter in the code, and some exceptions : one or several forms are dominant (> 90%), while the others are rare.
The analyzed code has less than 10% of the rare delimiters. For consistency reasons, it is recommended to make them all the same.
Generally, one or two delimiters are used, depending on the expected special chars in the scanned strings : for example, / tends to be avoided when parsing HTML.
Regex are literals, or partial literals, used in preg_match(), preg_match_all(), preg_replace(), preg_replace_callback(), preg_replace_callback_array().
<?php
echo 'a';
echo 'b';
echo 'c';
echo 'd';
echo 'e';
echo 'f';
echo 'g';
echo 'h';
echo 'i';
echo 'j';
echo 'k';
// This should probably be written 'echo';
print 'l';
?>
See also Ideal regex delimiters in PHP.
1.2.1205.1. Specs¶
Short name |
Structures/RegexDelimiter |
Rulesets |
|
Exakat since |
0.10.5 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1206. Repeated print()¶
Always merge several print or echo in one call.
It is recommended to use echo with multiple arguments, or a concatenation with print, instead of multiple calls to print echo, when outputting several blob of text.
<?php
//Write :
echo 'a', $b, 'c';
print 'a' . $b . 'c';
//Don't write :
print 'a';
print $b;
print 'c';
?>
1.2.1206.1. Suggestions¶
Merge all prints into one echo call, separating arguments by commas.
Collect all values in one variable, and do only one call to print or echo.
1.2.1206.2. Specs¶
Short name |
Structures/RepeatedPrint |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
ClearPHP |
|
Examples |
|
Available in |
1.2.1207. Repeated Regex¶
Repeated regex should be centralized.
When a regex is repeatedly used in the code, it is getting harder to update.
<?php
// Regex used several times, at least twice.
preg_match('/^abc_|^square$/i', $_GET['x']);
//.......
preg_match('/^abc_|^square$/i', $row['name']);
// This regex is dynamically built, so it is not reported.
preg_match('/^circle|^'.$x.'$/i', $string);
// This regex is used once, so it is not reported.
preg_match('/^circle|^square$/i', $string);
?>
Regex that are repeated at least once (aka, used twice or more) are reported. Regex that are dynamically build are not reported.
1.2.1207.1. Suggestions¶
Create a central library of regex
Use the regex inventory to spot other regex that are close, and should be identical.
1.2.1207.2. Specs¶
Short name |
Structures/RepeatedRegex |
Rulesets |
|
Exakat since |
0.10.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1208. Resources Usage¶
List of situations that are creating resources.
<?php
// This functioncall creates a resource to use
$fp = fopen('/tmp/file.txt', 'r');
if (!is_resource($fp)){
thrown new RuntimeException('Could not open file.txt');
}
?>
1.2.1208.1. Specs¶
Short name |
Structures/ResourcesUsage |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1209. Results May Be Missing¶
preg_match() may return empty values, if the search fails. It is important to check for the existence of results before assigning them to another variable, or using it.
<?php
preg_match('/PHP ([0-9\.]+) /', $res, $r);
$s = $r[1];
// $s may end up null if preg_match fails.
?>
1.2.1209.1. Specs¶
Short name |
Structures/ResultMayBeMissing |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1210. Return True False¶
These conditional expressions return true/false, depending on the condition. This may be simplified by dropping the control structure altogether.
<?php
if (version_compare($a, $b) >= 0) {
return true;
} else {
return false;
}
?>
This may be simplified with :
<?php
return version_compare($a, $b) >= 0;
?>
This may be applied to assignations and ternary operators too.
<?php
if (version_compare($a, $b) >= 0) {
$a = true;
} else {
$a = false;
}
$a = version_compare($a, $b) >= 0 ? false : true;
?>
1.2.1210.1. Suggestions¶
Return directly the comparison, without using the if/then structure
Cast the value to (boolean) and use it instead of the ternary
1.2.1210.2. Specs¶
Short name |
Structures/ReturnTrueFalse |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1211. Return void¶
Return returns null as default value. It is recommended to mention explicitly ‘null’ or find a meaningful return such as a boolean or a default value instead.
<?php
function foo(&$a) {
++$a;
// No explicit return : it returns void
}
function bar(&$a) {
++$a;
// Explicit return : it returns null
return null
}
?>
See also Void functions.
1.2.1211.1. Specs¶
Short name |
Structures/ReturnVoid |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.1212. Reuse Variable¶
A variable is already holding the content that is calculated multiple times over.
It is recommended to use the cached value. This saves some computation, in particular when used in a loop, and speeds up the process.
<?php
function foo($a) {
$b = strtolower($a);
// strtolower($a) is already calculated in $b. Just reuse the value.
if (strtolower($a) === 'c') {
doSomething();
}
}
?>
1.2.1212.1. Suggestions¶
Reuse the already created variable
1.2.1212.2. Specs¶
Short name |
Structures/ReuseVariable |
Rulesets |
|
Exakat since |
1.1.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
Medium |
Available in |
1.2.1213. Static Global Variables Confusion¶
It is recommended to avoid using the same name for a global variable and a static variable.
<?php
function foo() {
$a = 1; // $a is a local variable
global $a; // $a is now a global variable
static $a; // $a is not w static variable
}
?>
1.2.1213.1. Suggestions¶
Avoid using static variables
Avoid using global variables
Avoid using the same name for static and global variables
1.2.1213.2. Specs¶
Short name |
Structures/SGVariablesConfusion |
Rulesets |
|
Exakat since |
2.1.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1214. Same Conditions In Condition¶
At least two consecutive if/then structures use identical conditions. The latter will probably be ignored.
This analysis returns false positive when there are attempt to fix a situation, or to call an alternative solution.
Conditions that are shared between if structures, but inside a logical OR expression are also detected.
<?php
if ($a == 1) { doSomething(); }
elseif ($b == 1) { doSomething(); }
elseif ($c == 1) { doSomething(); }
elseif ($a == 1) { doSomething(); }
else {}
// Also works on if then else if chains
if ($a == 1) { doSomething(); }
else if ($b == 1) { doSomething(); }
else if ($c == 1) { doSomething(); }
else if ($a == 1) { doSomething(); }
else {}
// Also works on if then else if chains
// Here, $a is common and sufficient in both conditions
if ($a || $b) { doSomething(); }
elseif ($a || $c) { doSomethingElse(); }
// This sort of situation generate false postive.
$config = load_config_from_commandline();
if (empty($config)) {
$config = load_config_from_file();
if (empty($config)) {
$config = load_default_config();
}
}
?>
1.2.1214.1. Suggestions¶
Merge the two conditions into one
Make the two conditions different
1.2.1214.2. Specs¶
Short name |
Structures/SameConditions |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Critical |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1215. Sequences In For¶
For() instructions allows several instructions in each of its parameters. Then, the instruction separator is comma ‘,’, not semi-colon, which is used for separating the 3 arguments.
<?php
for ($a = 0, $b = 0; $a < 10, $b < 20; $a++, $b += 3) {
// For loop
}
?>
This loop will simultaneously increment $a and $b. It will stop only when the last of the central sequence reach a value of false : here, when $b reach 20 and $a will be 6.
This structure is often unknown, and makes the for instruction quite difficult to read. It is also easy to oversee the multiples instructions, and omit one of them. It is recommended not to use it.
1.2.1215.1. Specs¶
Short name |
Structures/SequenceInFor |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1216. Set Aside Code¶
Setting aside code should be made into a method.
Setting aside code happens when one variable or member is stored locally, to be temporarily replaced by another value. Once the new value has been processed, the original value is reverted.
The temporary change of the value makes the code hard to read.
It is a good example of a piece of code that could be moved to a separate method or function. Using the temporary value as a parameter makes the change visible, and avoid local pollution.
<?php
// Setting aside database
class cache extends Storage {
private $database = null;
function __construct($database) {
$this->database = $database;
}
function foo($values) {
// handling storage with sqlite3
$secondary = new cache(new Sqlite3(':memory:'));
$secondary->store($values);
$this->store($values); // handling storage with injection
}
}
// Setting aside database to cache data in two distinct backend
class cache extends Storage {
private $database = null;
function __construct(\Pdo $database) {
$this->database = $database;
}
function foo($values) {
// $this->database is set aside for secondary configuration
$side = $this->database;
$this->database = new Sqlite3(':memory:');
$this->store($values); // handling storage with sqlite3
$this->database = $side;
// $this->database is restored
$this->store($values); // handling storage with injection
}
}
?>
1.2.1216.1. Suggestions¶
Extract the code that run with the temporary value to a separate method.
1.2.1216.2. Specs¶
Short name |
Structures/SetAside |
Rulesets |
|
Exakat since |
1.8.8 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1217. Setlocale() Uses Constants¶
setlocale() don’t use strings but constants.
The first argument of setlocale() must be one of the valid constants, LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY, LC_NUMERIC, LC_TIME, `LC_MESSAGES <https://www.php.net/LC_MESSAGES>`_.
<?php
// Use constantes for setlocale first argument
setlocale(LC_ALL, 'nl_NL');
setlocale(\LC_ALL, 'nl_NL');
// Don't use string for setlocale first argument
setlocale('LC_ALL', 'nl_NL');
setlocale('LC_'.'ALL', 'nl_NL');
?>
The PHP 5 usage of strings (same name as above, enclosed in ‘ or “) is not legit anymore in PHP 7 and later.
See also setlocale.
1.2.1217.1. Suggestions¶
Use setlocale() constants
1.2.1217.2. Specs¶
Short name |
Structures/SetlocaleNeedsConstants |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.1218. Shell Usage¶
List of shell calls to system.
<?php
// Using backtick operator
$a = `ls -hla`;
// Using one of PHP native or extension functions
$a = shell_exec('ls -hla');
$b = \pcntl_exec('/path/to/command');
?>
See also shell_exec and Execution Operators.
1.2.1218.1. Specs¶
Short name |
Structures/ShellUsage |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1219. Using Short Tags¶
The code makes use of short tags. Short tags are the following :
<?. A full scripts looks like that :<? /* php code */ ?>.
It is recommended to not use short tags, and use standard PHP tags. This makes PHP code compatible with XML standards. Short tags used to be popular, but have lost it.
See also PHP Tags.
1.2.1219.1. Specs¶
Short name |
Structures/ShortTags |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
7.0- |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
ClearPHP |
|
Available in |
1.2.1220. Should Chain Exception¶
Chain exception to provide more context.
When catching an exception and rethrowing another one, it is recommended to chain the exception : this means providing the original exception, so that the final recipient has a chance to track the origin of the problem. This doesn’t change the thrown message, but provides more information.
Note : Chaining requires PHP > 5.3.0.
<?php
try {
throw new Exception('Exception 1', 1);
} catch (\Exception $e) {
throw new Exception('Exception 2', 2, $e);
// Chaining here.
}
?>
See also Exception::`__construct <https://www.php.net/manual/en/exception.construct.php>`_ and What are the best practices for catching and re-throwing exceptions?.
1.2.1220.1. Suggestions¶
Add the incoming exception to the newly thrown exception
1.2.1220.2. Specs¶
Short name |
Structures/ShouldChainException |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1221. Should Make Ternary¶
Ternary operators are the best when assigning values to a variable.
This way, they are less verbose, compatible with assignation and easier to read.
<?php
// verbose if then structure
if ($a == 3) {
$b = 2;
} else {
$b = 3;
}
// compact ternary call
$b = ($a == 3) ? 2 : 3;
// verbose if then structure
// Works with short assignations and simple expressions
if ($a != 3) {
$b += 2 - $a * 4;
} else {
$b += 3;
}
// compact ternary call
$b += ($a != 3) ? 2 - $a * 4 : 3;
?>
See also Ternary Operator and Shorthand comparisons in PHP.
1.2.1221.1. Specs¶
Short name |
Structures/ShouldMakeTernary |
Rulesets |
|
Exakat since |
0.8.5 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1222. Preprocessable¶
The following expression are made of literals or already known values : they may be fully calculated before running PHP.
<?php
// Building an array from a string
$name = 'PHP'.' '.'7.2';
// Building an array from a string
$list = explode(',', 'a,b,c,d,e,f');
// Calculating a power
$kbytes = $bytes / pow(2, 10);
// This will never change
$name = ucfirst(strtolower('PARIS'));
?>
By doing so, this will reduce the amount of work of PHP.
1.2.1222.1. Suggestions¶
Do the work yourself, instead of giving it to PHP
1.2.1222.2. Specs¶
Short name |
Structures/ShouldPreprocess |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1223. Should Use Explode Args¶
explode() has a third argument, which limits the amount of exploded elements. With it, it is possible to collect only the first elements, or drop the last ones.
<?php
$exploded = explode(DELIMITER, $string);
// use explode(DELIMITER, $string, -1);
array_pop($exploded);
// use explode(DELIMITER, $string, -2);
$c = array_slice($exploded, 0, -2);
// with explode()'s third argument :
list($a, $b) = explode(DELIMITER, $string, 2);
// with list() omitted arguments
list($a, $b, ) = explode(DELIMITER, $string);
?>
See also explode.
1.2.1223.1. Specs¶
Short name |
Structures/ShouldUseExplodeArgs |
Rulesets |
|
Exakat since |
1.9.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1224. Should Use Foreach¶
Use foreach instead of for when traversing an array.
Foreach() is the modern loop : it maps automatically every element of the array to a blind variable, and loop over it. This is faster and safer.
<?php
// Foreach version
foreach($array as $element) {
doSomething($element);
}
// The above case may even be upgraded with array_map and a callback,
// for the simplest one of them
$array = array_map('doSomething', $array);
// For version (one of various alternatives)
for($i = 0; $i < count($array); $i++) {
$element = $array[$i];
doSomething($element);
}
// Based on array_pop or array_shift()
while($value = array_pop($array)) {
doSomething($array);
}
?>
See also foreach and 5 Ways To Loop Through An Array In PHP.
1.2.1224.1. Suggestions¶
Move for() loops to foreach(), whenever they apply to a finite list of elements
1.2.1224.2. Specs¶
Short name |
Structures/ShouldUseForeach |
Rulesets |
|
Exakat since |
0.12.7 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1225. Should Use Math¶
Use math operators to make the operation readable.
<?php
// Adding one to self
$a *= 2;
// same as above
$a += $a;
// Squaring oneself
$a \*\*\= 2;
// same as above
$a *= $a;
// Removing oneself
$a = 0;
// same as above
$a -= $a;
// Dividing oneself
$a = 1;
// same as above
$a /= $a;
// Divisition remainer
$a = 0;
// same as above
$a %= $a;
?>
See also Mathematical Functions.
1.2.1225.1. Suggestions¶
Use explicit math assignation
1.2.1225.2. Specs¶
Short name |
Structures/ShouldUseMath |
Rulesets |
|
Exakat since |
1.1.5 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1226. Should Use Operator¶
Some functions duplicate the feature of an operator. When in doubt, it is better to use the operator.
Beware, some edge cases may apply. In particular, backward compatibility may prevent usage of newer features.
array_push() is equivalent to []
is_object() is equivalent to instanceof
function_get_arg() and function_get_args() is equivalent to ellipsis : …
chr() is equivalent to string escape sequences, such as
\n,\x69,u{04699}call_user_func() is equivalent to
$functionName(arguments),$object->$method(`... <https://www.php.net/manual/en/functions.arguments.php#functions.variable-arg-list>`_$arguments)is_null() is equivalent to
=== nullphp_version() is equivalent to
PHP_VERSION(the constant)is_array(), is_int(), is_object(), etc. is equivalent to a scalar typehint
1.2.1226.1. Suggestions¶
Use [] instead of array_push()
Use instanceof instead of is_object()
Use … instead of function_get_arg() and function_get_args()
Use escape sequences instead of chr()
Use dynamic function call instead of call_user_func()
Use === null instead of is_null()
Use PHP_VERSION instead of php_version()
Use typehint instead of is_int(), is_string(), is_bool(), etc.
1.2.1226.2. Specs¶
Short name |
Structures/ShouldUseOperator |
Rulesets |
|
Exakat since |
1.3.0 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1227. Simplify Regex¶
Avoid using regex when the searched string or the replacement are simple enough.
PRCE regex are a powerful way to search inside strings, but they also come at the price of performance. When the query is simple enough, try using strpos() or stripos() instead.
<?php
// simple preg calls
if (preg_match('/a/', $string)) {}
if (preg_match('/b/i', $string)) {} // case insensitive
// light replacements
if( strpos('a', $string)) {}
if( stripos('b', $string)) {} // case insensitive
?>
1.2.1227.1. Suggestions¶
Use str_replace(), strtr() or even strpos()
1.2.1227.2. Specs¶
Short name |
Structures/SimplePreg |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1228. Static Loop¶
Static loop may be preprocessed.
It looks like the following loops are static : the same code is executed each time, without taking into account loop variables.
<?php
// Static loop
$total = 0;
for($i = 0; $i < 10; $i++) {
$total += $i;
}
// The above loop may be replaced by (with some math help)
$total = 10 * (10 + 1) / 2;
// Non-Static loop (the loop depends on the size of the array)
$n = count($array);
for($i = 0; $i < $n; $i++) {
$total += $i;
}
?>
It is possible to create loops that don’t use any blind variables, though this is fairly rare. In particular, calling a method may update an internal pointer, like next() or SimpleXMLIterator\:\:`next() <https://www.php.net/next>`_.
It is recommended to turn a static loop into an expression that avoid the loop. For example, replacing the sum of all integers by the function $n * ($n + 1) / 2, or using array_sum().
This analysis doesn’t detect usage of variables with compact.
1.2.1228.1. Suggestions¶
Precalculate the result of that loop and removes it altogether
Check that the loop is not missing a blind variable usage
Replace the usage of a loop with a native PHP call : for example, with str_repeat(). Although the loop is still here, it usually reflects better the intend.
1.2.1228.2. Specs¶
Short name |
Structures/StaticLoop |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1229. strip_tags Skips Closed Tag¶
strip_tags() skips non-self closing tags. This means that tags such as
<br />will be ignored from the 2nd argument of the function.
<?php
$input = 'a<br />';
// Displays 'a' and clean the tag
echo strip_tags($input, '<br>');
// Displays 'a<br />' and skips the allowed tag
echo strip_tags($input, '<br/>');
?>
See also strip_tags.
1.2.1229.1. Suggestions¶
Do not use self-closing tags in the 2nd parameter
1.2.1229.2. Specs¶
Short name |
Structures/StripTagsSkipsClosedTag |
Rulesets |
|
Exakat since |
1.9.3 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1230. Strpos()-like Comparison¶
The result of that function may be mistaken with an error.
strpos(), along with several PHP native functions, returns a string position, starting at 0, or false, in case of failure.
<?php
// This is the best comparison
if (strpos($string, 'a') === false) { }
// This is OK, as 2 won't be mistaken with false
if (strpos($string, 'a') == 2) { }
// strpos is one of the 26 functions that may behave this way
if (preg_match($regex, $string)) { }
// This works like above, catching the value for later reuse
if ($a = strpos($string, 'a')) { }
// This misses the case where 'a' is the first char of the string
if (strpos($string, 'a')) { }
// This misses the case where 'a' is the first char of the string, just like above
if (strpos($string, 'a') == 0) { }
?>
It is recommended to check the result of strpos() with === or !==, so as to avoid confusing 0 and false.
This analyzer list all the strpos()-like functions that are directly compared with == or !=. preg_match(), when its first argument is a literal, is omitted : this function only returns NULL in case of regex error.
The full list is the following :
In PHP 8.0, str_contains() will do the expected job of strpos(), with less confusion.
See also strpos not working correctly.
1.2.1230.1. Suggestions¶
Use identity comparisons, for 0 values : === instead of ==, etc.
Compare with other exact values than 0 : strpos() == 2
Use str_contains()
1.2.1230.2. Specs¶
Short name |
Structures/StrposCompare |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
ClearPHP |
|
Examples |
|
Available in |
1.2.1231. Drop Substr Last Arg¶
Substr() works till the end of the string when the last argument is omitted. There is no need to calculate string size to make this work.
<?php
$string = 'abcdef';
// Extract the end of the string
$cde = substr($string, 2);
// Too much work
$cde = substr($string, 2, strlen($string));
?>
See also substr.
1.2.1231.1. Suggestions¶
Use negative length
Omit the last argument to get the string till its end
1.2.1231.2. Specs¶
Short name |
Structures/SubstrLastArg |
Rulesets |
|
Exakat since |
1.2.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1232. Substr To Trim¶
When removing the first or the last character of a string, trim() does a more readable job.
trim(), ltrim() and rtrim() accept a string as second argument. Those will all be removed from the endings of the string.
<?php
$a = '$drop the dollar';
$b = substr($a, 1); // drop the first char
$b = ltrim($a, '$'); // remove the initial '$'s
$b = substr($a, 1); // replace with ltrim()
$b = substr($a, 0, -1); // replace with rtrim()
$b = substr($a, 1, -1); // replace with trim()
?>
trim() will remove all occurrences of the requested char(). This may remove a loop with substr(), or remove more than is needed.
trim() doesn’t work with multi-bytes strings, but so does substr(). For that, use mb_substr(), as there isn’t any mb_trim function (yet).
1.2.1232.1. Suggestions¶
Replace substr() with trim(), ltrim() or rtrim().
1.2.1232.2. Specs¶
Short name |
Structures/SubstrToTrim |
Rulesets |
|
Exakat since |
1.8.3 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1233. Suspicious Comparison¶
The comparison seems to be misplaced.
A comparison happens in the last argument, while the actual function expect another type : this may be the case of a badly placed parenthesis.
<?php
// trim expect a string, a boolean is given.
if (trim($str === '')){
}
// Just move the first closing parenthesis to give back its actual meaning
if (trim($str) === ''){
}
?>
Original idea by Vladimir Reznichenko.
1.2.1233.1. Suggestions¶
Remove the comparison altogether
Move the comparison to its right place : that, or more the parenthesis.
This may be what is intended : just leave it.
1.2.1233.2. Specs¶
Short name |
Structures/SuspiciousComparison |
Rulesets |
|
Exakat since |
0.11.0 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1234. Switch To Switch¶
The following structures are based on if / elseif / else. Since they have more than three conditions (not withstanding the final else), it is recommended to use the switch structure, so as to make this more readable.
On the other hand, switch() structures with less than 3 elements should be expressed as a if / else structure.
Note that if condition that uses strict typing (=== or !==) can’t be converted to switch() as the latter only performs == or != comparisons.
<?php
if ($a == 1) {
} elseif ($a == 2) {
} elseif ($a == 3) {
} elseif ($a == 4) {
} else {
}
// Better way to write long if/else lists
switch ($a) {
case 1 :
doSomething(1);
break 1;
case 2 :
doSomething(2);
break 1;
case 3 :
doSomething(3);
break 1;
case 4 :
doSomething(4);
break 1;
default :
doSomething();
break 1;
}
?>
Note that simple switch statement, which compare a variable to a literal are optimised in PHP 7.2 and more recent. This gives a nice performance boost, and keep code readable.
See also PHP 7.2’s switch optimisations and Is Your Code Readable By Humans? Cognitive Complexity Tells You.
1.2.1234.1. Suggestions¶
Use a switch statement, rather than a long string of if/else
Use a match() statement, rather than a long string of if/else (PHP 8.0 +)
1.2.1234.2. Specs¶
Short name |
Structures/SwitchToSwitch |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1235. Switch With Too Many Default¶
Switch statements should only hold one default, not more. Check the code and remove the extra default.
PHP 7.0 won’t compile a script that allows for several default cases.
Multiple default happens often with large switch().
<?php
switch($a) {
case 1 :
break;
default :
break;
case 2 :
break;
default : // This default is never reached
break;
}
?>
1.2.1235.1. Suggestions¶
Remove the useless default : it may be the first, or the last. In case of ambiguity, keep the first, as it is the one being used at the moment.
1.2.1235.2. Specs¶
Short name |
Structures/SwitchWithMultipleDefault |
Rulesets |
CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, All |
Exakat since |
0.8.4 |
PHP Version |
7.0- |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1236. Switch Without Default¶
Switch statements hold a number of ‘case’ that cover all known situations, and a ‘default’ one which is executed when all other options are exhausted.
For Match statements, a missing default will lead to the UnhandledMatchError exception being raised. On the other hand, the switch statement will simply exit without action nor alert.
<?php
// Missing default
switch($format) {
case 'gif' :
processGif();
break 1;
case 'jpeg' :
processJpeg();
break 1;
case 'bmp' :
throw new UnsupportedFormat($format);
}
// In case $format is not known, then switch is ignored and no processing happens, leading to preparation errors
// switch with default
switch($format) {
case 'text' :
processText();
break 1;
case 'jpeg' :
processJpeg();
break 1;
case 'rtf' :
throw new UnsupportedFormat($format);
default :
throw new UnknownFileFormat($format);
}
// In case $format is not known, an exception is thrown for processing
?>
Most of the time, switch() do need a default case, so as to catch the odd situation where the ‘value is not what it was expected’. This is a good place to catch unexpected values, to set a default behavior.
1.2.1236.1. Suggestions¶
Add a default case
Catch the UnhandledMatchError exception
See also and UnhandledMatchError.
1.2.1236.2. Specs¶
Short name |
Structures/SwitchWithoutDefault |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
ClearPHP |
|
Examples |
|
Available in |
1.2.1237. Ternary In Concat¶
Ternary and coalesce operator have higher priority than dot ‘.’ for concatenation. This means that :
<?php
// print B0CE as expected
print 'B'.$b.'C'. ($b > 1 ? 'D') : 'E';
// print E, instead of B0CE
print 'B'.$b.'C'. $b > 1 ? 'D' : 'E';
print 'B'.$b.'C'. $b > 1 ? 'D' : 'E';
?>
prints actually ‘E’, instead of the awaited ‘B0CE’.
To be safe, always add parenthesis when using ternary operator with concatenation.
See also Operator Precedence.
1.2.1237.1. Suggestions¶
Use parenthesis
Avoid ternaries and coalesce operators inside a string
1.2.1237.2. Specs¶
Short name |
Structures/TernaryInConcat |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Critical |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1238. Test Then Cast¶
A test is run on the value, but the cast value is later used.
The cast may introduce a distortion to the value, and still lead to the unwanted situation. For example, comparing to 0, then later casting to an int. The comparison to 0 is done without casting, and as such, 0.1 is different from 0. Yet, (int) 0.1 is actually 0, leading to a Division by 0 error.
<?php
// Here. $x may be different from 0, but (int) $x may be 0
$x = 0.1;
if ($x != 0) {
$y = 4 / (int) $x;
}
// Safe solution : check the cast value.
if ( (int) $x != 0) {
$y = 4 / (int) $x;
}
?>
1.2.1238.1. Suggestions¶
Test with the cast value
1.2.1238.2. Specs¶
Short name |
Structures/TestThenCast |
Rulesets |
|
Exakat since |
1.1.6 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1239. Throws An Assignement¶
It is possible to throw an exception, and, in the same time, assign this exception to a variable.
However, the variable will never be used, as the exception is thrown, and any following code is not executed, unless the exception is caught in the same scope.
<?php
// $e is useful, though not by much
$e = new() Exception();
throw $e;
// $e is useless
throw $e = new Exception();
?>
1.2.1239.1. Suggestions¶
Drop the assignation
1.2.1239.2. Specs¶
Short name |
Structures/ThrowsAndAssign |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.1240. Timestamp Difference¶
time()andmicrotime()shouldn’t be used to calculate duration.
time() and microtime() are subject to variations, depending on system clock variations, such as daylight saving time difference (every spring and fall, one hour variation), or leap seconds, happening on June, 30th or December 31th, as announced by IERS.
<?php
// Calculating tomorow, same hour, the wrong way
// tomorrow is not always in 86400s, especially in countries with daylight saving
$tomorrow = time() + 86400;
// Good way to calculate tomorrow
$datetime = new DateTime('tomorrow');
?>
When the difference may be rounded to a larger time unit (rounding the difference to days, or several hours), the variation may be ignored safely.
When the difference is very small, it requires a better way to measure time difference, such as Ticks <https://www.php.net/manual/en/control-structures.declare.php#control-structures.declare.ticks>’_, `ext/hrtime <https://www.php.net/manual/en/book.hrtime.php>’_, or including a check on the actual time zone (``ini_get()` with ‘date.timezone’).
See also PHP `DateTime <https://www.php.net/`DateTime>`_ difference – it’s a trap! <http://blog.codebusters.pl/en/php-datetime-difference-trap/>`_ and PHP Daylight savings bug?.
1.2.1240.1. Suggestions¶
For small time intervals, use hrtime() functions
For larger time intervals, use add() method with
DateTime
1.2.1240.2. Specs¶
Short name |
Structures/TimestampDifference |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Examples |
|
Available in |
1.2.1241. Try With Finally¶
Indicates if a try use a finally statement.
<?php
try {
$a = doSomething();
} catch (Throwable $e) {
// Fix the problem
} finally {
// remove $a anyway
unset($a);
}
?>
See also Exceptions, to learn about catching an exception.
1.2.1241.1. Specs¶
Short name |
Structures/TryFinally |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
5.5+ |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
Very high |
Available in |
1.2.1242. Unchecked Resources¶
Resources are created, but never checked before being used. This is not safe.
Always check that resources are correctly created before using them.
<?php
// always check that the resource is created correctly
$fp = fopen($d,'r');
if ($fp === false) {
throw new Exception('File not found');
}
$firstLine = fread($fp);
// This directory is not checked : the path may not exist and return false
$uncheckedDir = opendir($pathToDir);
while(readdir($uncheckedDir)) {
// do something()
}
// This file is not checked : the path may not exist or be unreadable and return false
$fp = fopen($pathToFile);
while($line = freads($fp)) {
$text .= $line;
}
// unsafe one-liner : using bzclose on an unchecked resource
bzclose(bzopen('file'));
?>
See also resources.
1.2.1242.1. Suggestions¶
Add a check between the resource acquisition and its usage
1.2.1242.2. Specs¶
Short name |
Structures/UncheckedResources |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
ClearPHP |
|
Available in |
1.2.1243. Unconditional Break In Loop¶
Here, break may also be a return, a goto or a continue. They all branch out of the loop. Such statement are valid, but should be moderated with a condition.
<?php
// return in loop should be in
function summAll($array) {
$sum = 0;
foreach($array as $a) {
// Stop at the first error
if (is_string($a)) {
return $sum;
}
$sum += $a;
}
return $sum;
}
// foreach loop used to collect first element in array
function getFirst($array) {
foreach($array as $a) {
return $a;
}
}
?>
1.2.1243.1. Suggestions¶
Remove the loop and call the content of the loop once.
1.2.1243.2. Specs¶
Short name |
Structures/UnconditionLoopBreak |
Rulesets |
|
Exakat since |
0.12.16 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1244. Unkown Regex Options¶
Regex support in PHP accepts the following list of options :
eimsuxADJSUX.
All other letter used as option are not supported : depending on the situation, they may be ignored or raise an error.
<?php
// all options are available
if (preg_match('/\d+/isA', $string, $results)) { }
// p and h are not regex options, p is double
if (preg_match('/\d+/php', $string, $results)) { }
?>
See also Pattern Modifiers
1.2.1244.1. Suggestions¶
Remove the unknown options
Replace the option with a valid one
Fix any syntax typo in the regex
1.2.1244.2. Specs¶
Short name |
Structures/UnknownPregOption |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1245. Unpreprocessed Values¶
Preprocessing values is the preparation of values before PHP executes the code.
There is no macro language in PHP, that prepares the code before compilation, bringing some comfort and short syntax. Most of the time, one uses PHP itself to preprocess data.
For example :
<?php
$days_en = 'monday,tuesday,wednesday,thursday,friday,saturday,sunday';
$days_zh = '星期-,星期二,星期三,星期四,星期五,星期六,星期日';
$days = explode(',', $lang === 'en' ? $days_en : $days_zh);
?>
could be written
<?php
if ($lang === 'en') {
$days = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday'];
} else {
$days = ['星期-', '星期二', '星期三', '星期四', '星期五', '星期六', '星期日'];
}
?>
and avoid preprocessing the string into an array first.
Preprocessing could be done anytime the script includes all the needed values to process the expression.
1.2.1245.1. Suggestions¶
Preprocess the values and hardcode them in PHP. Do not use PHP to calculate something at the last moment.
Use already processed values, or cache to avoid calculating the value each hit.
Create a class that export the data in the right format for every situation, including the developer’s comfort.
1.2.1245.2. Specs¶
Short name |
Structures/Unpreprocessed |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
ClearPHP |
|
Examples |
|
Available in |
1.2.1246. Unreachable Code¶
Code may be unreachable, because other instructions prevent its reaching.
For example, it be located after throw, return, exit() <https://www.php.net/`exit>`_, die() <https://www.php.net/`die>`_, goto, break or continue : this way, it cannot be reached, as the previous instruction will divert the engine to another part of the code.
<?php
function foo() {
$a++;
return $a;
$b++; // $b++ can't be reached;
}
function bar() {
if ($a) {
return $a;
} else {
return $b;
}
$b++; // $b++ can't be reached;
}
foreach($a as $b) {
$c += $b;
if ($c > 10) {
continue 1;
} else {
$c--;
continue;
}
$d += $e; // this can't be reached
}
$a = 1;
goto B;
class foo {} // Definitions are accessible, but not functioncalls
B:
echo $a;
?>
This is dead code, that may be removed.
1.2.1246.1. Suggestions¶
Remove the unreachable code
Remove the blocking expression, and let the code execute
1.2.1246.2. Specs¶
Short name |
Structures/UnreachableCode |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Instant (5 mins) |
Precision |
High |
ClearPHP |
|
Available in |
1.2.1247. Unset In Foreach¶
Unset applied to the variables of a
foreachloop are useless. Those variables are copies and not the actual value. Even if the value is a reference, unsetting it has no effect on the original array : the only effect may be indirect, on elements inside an array, or on properties inside an object.
<?php
// When unset is useless
$array = [1, 2, 3];
foreach($array as $a) {
unset($a);
}
print_r($array); // still [1, 2, 3]
foreach($array as $b => &$a) {
unset($a);
}
print_r($array); // still [1, 2, 3]
// When unset is useful
$array = [ [ 'c' => 1] ]; // Array in array
foreach($array as &$a) {
unset(&$a['c']);
}
print_r($array); // now [ ['c' => null] ]
?>
See also foreach.
1.2.1247.1. Suggestions¶
Drop the unset
1.2.1247.2. Specs¶
Short name |
Structures/UnsetInForeach |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1248. Unsupported Operand Types¶
This error is raised when trying to combine an array and a scalar value.
Always checks that the types are compatible with the planned operations.
<?php
const MY_ARRAY = 'error';
// This leads to the infamous Unsupported operand types error
$b = MY_ARRAY + array(3,4);
?>
PHP detects this error at linting time, when using literal values. When static expression are involved, this error will appear at execution time.
See also PHP - Fatal error: Unsupported operand types [duplicate].
1.2.1248.1. Suggestions¶
Make sure all the planned operations are compatible with the type used.
1.2.1248.2. Specs¶
Short name |
Structures/UnsupportedOperandTypes |
Rulesets |
none |
Exakat since |
1.7.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1249. Unsupported Types With Operators¶
Arrays, resources and objects are generally not accepted with unary and binary operators.
The operators are +, -, *, /, **, %, <<, >>, &, |, ^, ~, ++ and –.
<?php
var_dump([] % [42]);
// int(0) in PHP 7.x
// TypeError in PHP 8.0 +
// Also impossible usage : index are string or int
$a = [];
$b = $c[$a];
?>
In PHP 8.0, the rules have been made stricter and more consistent.
The only valid operator is +, combined with arrays in both operands. Other situation will throw TypeError.
1.2.1249.1. Suggestions¶
Do not use those values with those operators
Use a condition to skip this awkward situation
Add an extra step to turn this value into a valid type
See also Stricter type checks for arithmetic/bitwise operators and TypeError.
1.2.1249.2. Specs¶
Short name |
Structures/UnsupportedTypesWithOperators |
Rulesets |
|
Exakat since |
2.1.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Medium |
Available in |
1.2.1250. Unused Global¶
A global keyword is used in a method, yet the variable is not actually used. This makes PHP import values for nothing, or may create interference
<?php
function foo() {
global bar;
return 1;
}
?>
1.2.1250.1. Suggestions¶
Remove the global declaration
Remove the global variable altogether
1.2.1250.2. Specs¶
Short name |
Structures/UnusedGlobal |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1251. Unused Label¶
Some labels have been defined in the code, but they are not used. They may be removed as they are dead code.
<?php
$a = 0;
A:
++$a;
// A loop. A: is used
if ($a < 10) { goto A; }
// B is never called explicitely. This is useless.
B:
?>
There is no analysis for undefined goto call, as PHP checks that goto has a destination label at compile time :
See also Goto.
1.2.1251.1. Suggestions¶
Remove the unused label
Add a goto call to this label
Check for spelling mistakes
1.2.1251.2. Specs¶
Short name |
Structures/UnusedLabel |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1252. Use Array Functions¶
There are a lot of native PHP functions for arrays. It is often faster to take advantage of them than write a loop.
array_push() : use array_merge()
array_slice() : use array_chunk()
index access : use array_column()
append []: use array_merge()
addition : use array_sum()
multiplication : use array_product()
concatenation : use implode()
ifthen : use array_filter()
<?php
$all = implode('-', $s).'-';
// same as above
$all = '';
foreach($array as $s) {
$all .= $s . '-';
}
?>
- See also Array Functions and
1.2.1252.1. Suggestions¶
Remove the loop and use a native PHP function
Add more expressions to the loop : batching multiple operations in one loop makes it more interesting than running separates loops.
1.2.1252.2. Specs¶
Short name |
Structures/UseArrayFunctions |
Rulesets |
|
Exakat since |
1.8.8 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1253. Use Case Value¶
When switch() has branched to the right case, the value of the switched variable is know : it is the case.
This doesn’t work with complex expression cases, nor with default.
<?php
switch($a) {
case 'a' :
// $a == 'a';
echo $a;
break;
case 'b' :
// $a == 'b';
echo 'b';
break;
}
?>
1.2.1253.1. Suggestions¶
Use the literal value in the case, to avoid unnecessary computation.
1.2.1253.2. Specs¶
Short name |
Structures/UseCaseValue |
Rulesets |
|
Exakat since |
1.9.6 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1254. Use Constant¶
The following functioncall have a constant equivalent, that is faster to use than calling the functions.
This applies to the following functions :
pi() : replace with M_PI
phpversion() : replace with PHP_VERSION
php_sapi_name() : replace with PHP_SAPI_NAME
<?php
// recommended way
echo PHP_VERSION;
// slow version
echo php_version();
?>
See also PHP why `pi() and M_PI <https://stackoverflow.com/questions/42021176/php-why-pi-and-m-pi>`_.
1.2.1254.1. Suggestions¶
Use the constant version, not the function.
1.2.1254.2. Specs¶
Short name |
Structures/UseConstant |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.1255. Use Count Recursive¶
The code could use the recursive version of count.
The second argument of count, when set to COUNT_RECURSIVE, count recursively the elements. It also counts the elements themselves.
<?php
$array = array( array(1,2,3), array(4,5,6));
print (count($array, COUNT_RECURSIVE) - count($array, COUNT_NORMAL));
$count = 0;
foreach($array as $a) {
$count += count($a);
}
print $count;
?>
See also count.
1.2.1255.1. Suggestions¶
Drop the loop and use the 2nd argument of count()
1.2.1255.2. Specs¶
Short name |
Structures/UseCountRecursive |
Rulesets |
|
Exakat since |
1.1.7 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Examples |
|
Available in |
1.2.1256. Use Debug¶
The code source includes calls to debug functions.
The following debug functions and libraries are reported :
PHP native functions : print_r(), var_dump(), debug_backtrace(), debug_print_backtrace(), debug_zval_dump()
<?php
// Example with Zend Debug
Zend\Debug\Debug::dump($var, $label = null, $echo = true);
?>
1.2.1256.1. Specs¶
Short name |
Structures/UseDebug |
Rulesets |
|
Exakat since |
0.11.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1257. Avoid get_class()¶
get_class()should be replaced with theinstanceofoperator to check the class of an object.
get_class() only compares the full namespace name of the object’s class, while instanceof actually resolves the name, using the local namespace and aliases.
<?php
use Stdclass as baseClass;
function foo($arg) {
// Slow and prone to namespace errors
if (get_class($arg) === 'Stdclass') {
// doSomething()
}
}
function bar($arg) {
// Faster, and uses aliases.
if ($arg instanceof baseClass) {
// doSomething()
}
}
?>
See also get_class and Instanceof.
1.2.1257.1. Specs¶
Short name |
Structures/UseInstanceof |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1258. Use List With Foreach¶
<?php
// Short way to assign variables
// Works on PHP 7.1, where list() accepts keys.
foreach($names as list('first' => $first, 'last' => $last)) {
doSomething($first, $last);
}
// Short way to assign variables
// Works on all PHP versions with numerically indexed arrays.
foreach($names as list($first, $last)) {
doSomething($first, $last);
}
// Long way to assign variables
foreach($names as $name) {
$first = $name['first'];
$last = $name['last'];
doSomething($first, $last);
}
?>
1.2.1258.1. Suggestions¶
Use the list keyword (or the short syntax), and simplify the array calls in the loop.
1.2.1258.2. Specs¶
Short name |
Structures/UseListWithForeach |
Rulesets |
|
Exakat since |
1.0.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Examples |
|
Available in |
1.2.1259. Use Positive Condition¶
Whenever possible, use a positive condition.
Positive conditions are easier to understand, and lead to less understanding problems. Negative conditions are not reported when else is not present.
<?php
// This is a positive condition
if ($a == 'b') {
doSomething();
} else {
doSomethingElse();
}
if (!empty($a)) {
doSomething();
} else {
doSomethingElse();
}
// This is a negative condition
if ($a == 'b') {
doSomethingElse();
} else {
doSomething();
}
// No need to force $a == 'b' with empty else
if ($a != 'b') {
doSomethingElse();
}
?>
1.2.1259.1. Suggestions¶
Invert the code in the if branches, and the condition
1.2.1259.2. Specs¶
Short name |
Structures/UsePositiveCondition |
Rulesets |
|
Exakat since |
0.8.6 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1260. Use System Tmp¶
It is recommended to avoid hardcoding the temporary file. It is better to rely on the system’s temporary folder, which is accessible with sys_get_temp_dir().
<?php
// Where the tmp is :
file_put_contents(sys_get_temp_dir().'/tempFile.txt', $content);
// Avoid hard-coding tmp folder :
// On Linux-like systems
file_put_contents('/tmp/tempFile.txt', $content);
// On Windows systems
file_put_contents('C:\WINDOWS\TEMP\tempFile.txt', $content);
?>
See also PHP: When is /tmp not /tmp?.
1.2.1260.1. Suggestions¶
Do not hardcode the temporary file, use the system’s
1.2.1260.2. Specs¶
Short name |
Structures/UseSystemTmp |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1261. Use Url Query Functions¶
PHP features several functions dedicated to processing URL’s query string.
Those functions include extra checks : for example, http_build_query() adds urlencode() call on the values, and allow for choosing the separator and the Query string format.
<?php
$data = array(
'foo' => 'bar',
'baz' => 'boom',
'cow' => 'milk',
'php' => 'hypertext processor'
);
// safe and efficient way to build a query string
echo http_build_query($data, '', '&') . PHP_EOL;
// slow way to produce a query string
foreach($data as $name => &$value) {
$value = $name.'='.$value;
}
echo implode('&', $data) . PHP_EOL;
?>
1.2.1261.1. Specs¶
Short name |
Structures/UseUrlQueryFunctions |
Rulesets |
|
Exakat since |
1.9.7 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1262. Useless Brackets¶
Standalone brackets have no use. Brackets are used to delimit a block of code, and are used by control statements. They may also be used to protect variables in strings.
Standalone brackets may be a left over of an old instruction, or a misunderstanding of the alternative syntax.
<?php
// The following brackets are useless : they are a leftover from an older instruction
// if (DEBUG)
{
$a = 1;
}
// Here, the extra brackets are useless
for($a = 2; $a < 5; $a++) : {
$b++;
} endfor;
?>
1.2.1262.1. Suggestions¶
Remove the brackets
Restore the flow-control operation that was there and removed
Move the block into a method or function, and call it
1.2.1262.2. Specs¶
Short name |
Structures/UselessBrackets |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1263. Useless Type Casting¶
There is no need to overcast returned values.
<?php
// trim always returns a string : cast is useless
$a = (string) trim($b);
// strpos doesn't always returns an integer : cast is useful
$a = (boolean) strpos($b, $c);
// comparison don't need casting, nor parenthesis
$c = (bool) ($b > 2);
?>
See also Type juggling.
1.2.1263.1. Suggestions¶
Remove the type cast
1.2.1263.2. Specs¶
Short name |
Structures/UselessCasting |
Rulesets |
|
Exakat since |
0.8.7 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
Very high |
Examples |
|
Available in |
1.2.1264. Useless Check¶
There is no need to check the size of an array content before using foreach. Foreach() applies a test on the source, and skips the loop if no element is found.
<?php
// Checking for type is good.
if (is_array($array)) {
foreach($array as $a) {
doSomething($a);
}
}
// Foreach on empty arrays doesn't start. Checking is useless
if (!empty($array)) {
foreach($array as $a) {
doSomething($a);
}
}
?>
This analysis checks for conditions with sizeof() and count(). Conditions with isset() and empty() are omitted : they also check for the variable existence, and thus, offer extra coverage.
See also foreach.
1.2.1264.1. Suggestions¶
Drop the condition and the check
Turn the condition into isset(), empty() and is_array()
1.2.1264.2. Specs¶
Short name |
Structures/UselessCheck |
Rulesets |
|
Exakat since |
0.8.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1265. Useless Global¶
Global are useless in two cases. First, on super-globals, which are always globals, like $_GET; secondly, on variables that are not used.
<?php
// $_POST is already a global : it is in fact a global everywhere
global $_POST;
// $unused is useless
function foo() {
global $used, $unused;
++$used;
}
?>
Also, PHP has superglobals, a special team of variables that are always available, whatever the context. They are : $GLOBALS, $_SERVER, $_GET, $_POST, $_FILES, $_COOKIE, $_SESSION, $_REQUEST and $_ENV.
1.2.1265.1. Suggestions¶
Drop the global expression
1.2.1265.2. Specs¶
Short name |
Structures/UselessGlobal |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1266. Useless Instructions¶
Those instructions are useless, or contains useless parts.
For example, an addition whose result is not stored in a variable, or immediately used, does nothing : it is actually performed, and the result is lost. Just plain lost. In fact, PHP might detect it, and optimize it away.
Here the useless instructions that are spotted :
<?php
// Concatenating with an empty string is useless.
$string = 'This part '.$is.' useful but '.$not.'';
// This is a typo, that PHP turns into a constant, then a string, then nothing.
continue;
// Empty string in a concatenation
$a = 'abc' . '';
// Returning expression, whose result is not used (additions, comparisons, properties, closures, new without =, ...)
1 + 2;
// Returning post-incrementation
function foo($a) {
return $a++;
}
// array_replace() with only one argument
$replaced = array_replace($array);
// array_replace() is OK with ...
$replaced = array_replace(...$array);
// @ operator on source array, in foreach, or when assigning literals
$array = @array(1,2,3);
// Multiple comparisons in a for loop : only the last is actually used.
for($i = 0; $j = 0; $j < 10, $i < 20; ++$j, ++$i) {
print $i.' '.$j.PHP_EOL;
}
// Counting the keys and counting the array is the same.
$c = count(array_keys($array))
//array_keys already provides an array with only unique values, as they were keys in a previous array
$d = array_unique(array_keys($file['messages']))
// No need for assignation inside the ternary operator
$closeQuote = $openQuote[3] === "'" ? substr($openQuote, 4, -2) : $closeQuote = substr($openQuote, 3);
?>
1.2.1266.1. Suggestions¶
Remove the extra semi-colon
Remove the useless instruction
Assign this expression to a variable and make use of it
1.2.1266.2. Specs¶
Short name |
Structures/UselessInstruction |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
ClearPHP |
|
Available in |
1.2.1267. Useless Parenthesis¶
Situations where parenthesis are not necessary, and may be removed.
Parenthesis group several elements together, and allows for a more readable expression. They are used with logical and mathematical expressions. They are necessary when the precedence of the operators are not the intended execution order : for example, when an addition must be performed before the multiplication.
Sometimes, the parenthesis provide the same execution order than the default order : they are deemed useless.
<?php
if ( ($condition) ) {}
while( ($condition) ) {}
do $a++; while ( ($condition) );
switch ( ($a) ) {}
$y = (1);
($y) == (1);
f(($x));
// = has precedence over ==
($a = $b) == $c;
($a++);
// No need for parenthesis in default values
function foo($c = ( 1 + 2) ) {}
?>
See also Operators Precedence.
1.2.1267.1. Suggestions¶
Remove useless parenthesis, unless they are important for readability.
1.2.1267.2. Specs¶
Short name |
Structures/UselessParenthesis |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1268. Useless Switch¶
This switch has only one case. It may very well be replaced by a ifthen structure.
<?php
switch($a) {
case 1:
doSomething();
break;
}
// Same as
if ($a == 1) {
doSomething();
}
?>
1.2.1268.1. Suggestions¶
Turn the switch into a if/then for better readability
Add other cases to the switch, making it adapted to the situation
1.2.1268.2. Specs¶
Short name |
Structures/UselessSwitch |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1269. Useless Unset¶
There are situations where trying to remove a variable is actually useless.
PHP ignores any command that tries to unset a global variable, a static variable, or a blind variable from a foreach loop.
This is different from the garbage collector, which is run on its own schedule. It is also different from an explicit unset, aimed at freeing memory early : those are useful.
<?php
function foo($a) {
// unsetting arguments is useless
unset($a);
global $b;
// unsetting global variable has no effect
unset($b);
static $c;
// unsetting static variable has no effect
unset($c);
foreach($d as &$e){
// unsetting a blind variable is useless
(unset) $e;
}
// Unsetting a blind variable AFTER the loop is good.
unset($e);
}
?>
See also unset.
1.2.1269.1. Suggestions¶
Remove the unset
Set the variable to null : the effect is the same on memory, but the variable keeps its existence.
Omit unsetting variables, and wait for the end of the scope. That way, PHP free memory en mass.
1.2.1269.2. Specs¶
Short name |
Structures/UselessUnset |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
ClearPHP |
|
Examples |
|
Available in |
1.2.1270. var_dump()… Usage¶
var_dump(), print_r() or var_export() should not be left in any production code. They are debugging functions.
<?php
if ($error) {
// Debugging usage of var_dump
// And major security problem
var_dump($query);
// This is OK : the $query is logged, and not displayed
$this->log(print_r($query, true));
}
?>
They may be tolerated during development time, but must be removed so as not to have any chance to be run in production.
1.2.1270.1. Suggestions¶
Remove usage of var_dump(), print_r(), var_export() without 2nd argument, and other debug functions.
Push all logging to an external file, instead of the browser.
1.2.1270.2. Specs¶
Short name |
Structures/VardumpUsage |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Critical |
Time To Fix |
Instant (5 mins) |
Precision |
High |
ClearPHP |
|
Examples |
|
Available in |
1.2.1271. Variable Global¶
Variable global such are valid in PHP 5.6, but no in PHP 7.0. They should be replaced with ${$foo->bar}.
<?php
// Forbidden in PHP 7
global $normalGlobal;
// Forbidden in PHP 7
global $$variable->global ;
// Tolerated in PHP 7
global ${$variable->global};
?>
1.2.1271.1. Specs¶
Short name |
Structures/VariableGlobal |
Rulesets |
CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, All |
Exakat since |
0.8.3 |
PHP Version |
7.0- |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1272. Declare Global Early¶
Static and global keywords should be used as early as possible in a method.
Performance wise, it is better to call global or static only before using the variable.
Human-wise, it is recommended to put global or static at the beginning of the method, for better readability.
<?php
function foo() {
// $a is not global yet. It is a local variable
$a = 1;
// Same for static variables
$s = 5;
// Now $a is global
global $a;
$a = 3;
// Now $s is static
static $s;
$s = 55;
}
?>
See also Using `static variables <https://www.php.net/manual/en/language.variables.scope.php#language.variables.scope.`static <https://www.php.net/manual/en/language.oop5.static.php>`_>`_ and The global keyword.
1.2.1272.1. Suggestions¶
Use static and global at the beginning of the method
Move static and global to the first usage of the variable
Remove any access to the variable before static and global
1.2.1272.2. Specs¶
Short name |
Structures/VariableMayBeNonGlobal |
Rulesets |
|
Exakat since |
1.5.3 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
Very high |
Available in |
1.2.1273. While(List() = Each())¶
This code structure is quite old : it should be replace by the more modern and efficient foreach.
This structure is deprecated since PHP 7.2. It may disappear in the future.
<?php
while(list($key, $value) = each($array)) {
doSomethingWith($key) and $value();
}
foreach($array as $key => $value) {
doSomethingWith($key) and $value();
}
?>
See also PHP RFC: Deprecations for PHP 7.2 : `Each() <https://wiki.php.net/rfc/deprecations_php_7_2#each>`_.
1.2.1273.1. Suggestions¶
Change this loop with foreach
Change this loop with an array_* function with a callback
1.2.1273.2. Specs¶
Short name |
Structures/WhileListEach |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1274. Wrong Range Check¶
The interval check should use && and not ||.
<?php
//interval correctly checked a is between 2 and 999
if ($a > 1 && $a < 1000) {}
//interval incorrectly checked : a is 2 or more ($a < 1000 is never checked)
if ($a > 1 || $a < 1000) {}
?>
1.2.1274.1. Suggestions¶
Make the interval easy to read and understand
Check the truth table for the logical operation
1.2.1274.2. Specs¶
Short name |
Structures/WrongRange |
Rulesets |
|
Exakat since |
1.2.5 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1275. Yoda Comparison¶
Yoda comparison is a way to write conditions which places literal values on the left side.
<?php
if (1 == $a) {
// Then condition
}
?>
The objective is to avoid mistaking a comparison to an assignation. If the comparison operator is mistaken, but the literal is on the left, then an error will be triggered, instead of a silent bug.
<?php
// error in comparison!
if ($a = 1) {
// Then condition
}
?>
See also Yoda Conditions, Yoda Conditions: To Yoda or Not to Yoda.
1.2.1275.1. Specs¶
Short name |
Structures/YodaComparison |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1276. preg_replace With Option e¶
preg_replace() supported the /e option until PHP 7.0. It allowed the use of eval()’ed expression as replacement. This has been dropped in PHP 7.0, for security reasons.
preg_replace() with /e option may be replaced with preg_replace_callback() and a closure, or preg_replace_callback_array() and an array of closures.
<?php
// preg_replace with /e
$string = 'abcde';
// PHP 5.6 and older usage of /e
$replaced = preg_replace('/c/e', 'strtoupper(\$0)', $string);
// PHP 7.0 and more recent
// With one replacement
$replaced = preg_replace_callback('/c/', function ($x) { return strtoupper($x[0]); }, $string);
// With several replacements, preventing multiple calls to preg_replace_callback
$replaced = preg_replace_callback_array(array('/c/' => function ($x) { return strtoupper($x[0]); },
'/[a-b]/' => function ($x) { return strtolower($x[0]); }), $string);
?>
1.2.1276.1. Suggestions¶
Replace call to preg_replace() and /e with preg_replace_callback() or preg_replace_callback_array()
1.2.1276.2. Specs¶
Short name |
Structures/pregOptionE |
Rulesets |
Analyze, CE, CI-checks, CompatibilityPHP70, CompatibilityPHP71, CompatibilityPHP72, Security, All |
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1277. __toString() Throws Exception¶
Magical method __toString() can’t throw exceptions.
In fact, __toString() may not let an exception pass. If it throw an exception, but must catch it. If an underlying method throws an exception, it must be caught.
<?php
class myString {
private $string = null;
public function __construct($string) {
$this->string = $string;
}
public function __toString() {
// Do not throw exceptions in __toString
if (!is_string($this->string)) {
throw new Exception("$this->string is not a string!!");
}
return $this->string;
}
}
?>
A fatal error is displayed, when an exception is not intercepted in the __toString() function.
::
PHP Fatal error: Method myString::__toString() must not throw an exception, caught Exception: ‘Exception message’ in
file.php
See also __toString().
1.2.1277.1. Suggestions¶
Remove any usage of exception from __toString() magic method
1.2.1277.2. Specs¶
Short name |
Structures/toStringThrowsException |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
7.4- |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1278. Already Parents Trait¶
Trait is already used a parent’s class or trait. There is no use to include it a second time.
<?php
trait ta {
use tb;
}
trait t1 {
use ta;
use tb; // also used by ta
}
class b {
use t1; // also required by class c
use ta; // also required by trait t1
}
class c extends b {
use t1;
}
?>
1.2.1278.1. Suggestions¶
Eliminate the trait in the parent class
Eliminate the trait in the child class
See also and Traits.
1.2.1278.2. Specs¶
Short name |
Traits/AlreadyParentsTrait |
Rulesets |
|
Exakat since |
1.8.0 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1279. Could Use Trait¶
The following classes have been found implementing all of a trait’s methods : it could use this trait, and remove duplicated code.
<?php
trait t {
function t1() {}
function t2() {}
function t3() {}
}
// t1, t2, t3 method could be dropped, and replaced with 'use t'
class foo1 {
function t1() {}
function t2() {}
function t3() {}
function j() {}
}
// foo2 is just the same as foo1
class foo2 {
use t;
function j() {}
}
?>
The comparison between the class methods’ and the trait’s methods are based on token. They may yield some false-positives.
See also Forgotten Interface.
1.2.1279.1. Suggestions¶
Use trait, and remove duplicated code
1.2.1279.2. Specs¶
Short name |
Traits/CouldUseTrait |
Rulesets |
|
Exakat since |
1.8.5 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1280. Dependant Trait¶
Traits should be autonomous. It is recommended to avoid depending on methods or properties that should be in the using class.
The following traits make usage of methods and properties, static or not, that are not defined in the trait. This means the host class must provide those methods and properties, but there is no way to enforce this.
This may also lead to dead code : when the trait is removed, the host class have unused properties and methods.
<?php
// autonomous trait : all it needs is within the trait
trait t {
private $p = 0;
function foo() {
return ++$this->p;
}
}
// dependant trait : the host class needs to provide some properties or methods
trait t2 {
function foo() {
return ++$this->p;
}
}
class x {
use t2;
private $p = 0;
}
?>
See also Dependant Abstract Classes.
1.2.1280.1. Suggestions¶
Add local property definitions to make the trait independent
Make the trait only use its own resources
Split the trait in autonomous traits
1.2.1280.2. Specs¶
Short name |
Traits/DependantTrait |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Examples |
|
Available in |
1.2.1281. Empty Traits¶
List of all empty trait defined in the code.
<?php
// empty trait
trait t { }
// Another empty trait
trait t2 {
use t;
}
?>
Such traits may be reserved for future use. They may also be forgotten, and dead code.
1.2.1281.1. Suggestions¶
Add some code to the trait
Remove the trait
1.2.1281.2. Specs¶
Short name |
Traits/EmptyTrait |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.1282. Is Extension Trait¶
Indicates if this trait is defined in an extension or not.
1.2.1282.1. Specs¶
Short name |
Traits/IsExtTrait |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1283. Locally Used Property In Trait¶
Properties that are used in the class where they are defined.
<?php
trait foo {
public $unused, $used;// property $unused is never used in this class
function bar() {
$this->used++; // property $used is used in this method
}
}
class X {
use foo;
}
$foo = new X();
$foo->unused = 'here'; // property $unused is used outside the trait definition
?>
1.2.1283.1. Specs¶
Short name |
Traits/LocallyUsedProperty |
Rulesets |
|
Exakat since |
1.3.5 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
Very high |
Available in |
1.2.1284. Method Collision Traits¶
Two or more traits are included in the same class, and they have methods collisions.
Those collisions should be solved with a use expression. When they are not, PHP stops execution with a fatal error : Trait method M has not been applied, because there are collisions with other trait methods on C.
<?php
trait A {
public function A() {}
public function M() {}
}
trait B {
public function B() {}
public function M() {}
}
class C {
use A, B;
}
class D {
use A, B{
B::M insteadof A;
};
}
?>
The code above lints, but doesn’t execute.
See also Traits.
1.2.1284.1. Specs¶
Short name |
Traits/MethodCollisionTraits |
Rulesets |
|
Exakat since |
1.4.2 |
PHP Version |
All |
Severity |
Critical |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1285. Multiple Usage Of Same Trait¶
The same trait is used several times. One trait usage is sufficient.
<?php
// C is used twice, and could be dropped from B
trait A { use B, C;}
trait B { use C;}
?>
PHP doesn’t raise any error when traits are included multiple times.
See also Traits.
1.2.1285.1. Suggestions¶
Remove any multiple traits from use expressions
Review the class tree, and remove any trait mentioned multiple times
1.2.1285.2. Specs¶
Short name |
Traits/MultipleUsage |
Rulesets |
|
Exakat since |
1.5.7 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1286. Redefined PHP Traits¶
List of all traits that bears name of a PHP trait. Although, at the moment, there are no PHP trait defined.
1.2.1286.1. Specs¶
Short name |
Traits/Php |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1287. Self Using Trait¶
Trait uses itself : this is unnecessary. Traits may use themselves, or be used by other traits, that are using the initial trait itself.
PHP handles the situation quietly, by ignoring all extra use of the same trait, keeping only one valid version.
<?php
// empty, but valid
trait a {}
// obvious self usage
trait b { use b; }
// less obvious self usage
trait c { use d, e, f, g, h, c; }
// level 2 self usage
trait i { use j; }
trait j { use i; }
?>
See also Traits.
1.2.1287.1. Suggestions¶
Remove the extra usage of the trait.
1.2.1287.2. Specs¶
Short name |
Traits/SelfUsingTrait |
Rulesets |
|
Exakat since |
1.5.7 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1288. Trait Methods¶
List the names of the methods in a trait.
<?php
trait t {
private $property = 1;
// This is an interface method name
function foo() {
// This is not a trait method
return function($a) { return $a + 1; }
}
}
?>
1.2.1288.1. Specs¶
Short name |
Traits/TraitMethod |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1289. Trait Not Found¶
A unknown trait is mentioned in the use expression.
The used traits all exist, but in the configuration block, some unmentioned trait is called.
Be aware that the traits used in any configuration block may originate in any use expression. PHP will check the configuration block at instantiation only, and after compiling : at that moment, it will know all the used traits across the class.
<?php
class x {
// c is not a used trait
use a, b { c::d insteadof e;}
// e is a used trait, even if is not in the use above.
use e;
}
?>
1.2.1289.1. Suggestions¶
Switch the name of the trait to an existing and used trait
Drop the expression that rely on the non-existent trait
See also and Traits.
1.2.1289.2. Specs¶
Short name |
Traits/TraitNotFound |
Rulesets |
|
Exakat since |
1.7.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1290. Traits Usage¶
Usage of traits in the code.
<?php
trait t {
function t() {
echo 'I\'m in t';
}
}
class foo {
use t;
}
$x = new foo();
$x->t();
?>
See also and Traits.
1.2.1290.1. Specs¶
Short name |
Traits/TraitUsage |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
Very high |
Available in |
1.2.1291. Trait Names¶
List all the traits names in the code.
<?php
// This trait is called 't'
trait t {}
?>
See also Traits.
1.2.1291.1. Specs¶
Short name |
Traits/Traitnames |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1292. Undefined Insteadof¶
Insteadoftries to replace a method with another, but it doesn’t exists. This happens when the replacing class is refactored, and some of its definition are dropped.
Insteadof may replace a non-existing method with an existing one, but not the contrary.
<?php
trait A {
function C (){}
}
trait B {
function C (){}
}
class Talker {
use A, B {
B::C insteadof A;
B::D insteadof A;
}
}
new Talker();
?>
This error is not linted : it only appears at execution time.
See also Traits.
1.2.1292.1. Suggestions¶
Remove the insteadof expression
Fix the original method and replace it with an existing method
1.2.1292.2. Specs¶
Short name |
Traits/UndefinedInsteadof |
Rulesets |
|
Exakat since |
1.4.2 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.1293. Undefined Trait¶
Those are undefined, traits .
When the using class or trait is instantiated, PHP emits a a fatal error.
<?php
use Composer/Component/someTrait as externalTrait;
trait t {
function foo() {}
}
// This class uses trait that are all known
class hasOnlyDefinedTrait {
use t, externalTrait;
}
// This class uses trait that are unknown
class hasUndefinedTrait {
use unknownTrait, t, externalTrait;
}
?>
Trait which are referenced in a use expression are omitted: they are considered part of code that is probably outside the current code, either omitted or in external component.
1.2.1293.1. Suggestions¶
Define the missing trait
Remove usage of the missing trait
1.2.1293.2. Specs¶
Short name |
Traits/UndefinedTrait |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Critical |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1294. Unused Trait In Class¶
A trait has been summoned in a class, but is not used. Traits may be used as a copy/paste of code, bringing a batch of methods and properties to a class. In the current case, the imported trait is never called. As such, it may be removed.
Currently, the analysis covers only traits that are used in the class where they are imported. Also, the properties are not covered yet.
<?php
trait t {
function foo() { return 1;}
}
// this class imports and uses the trait
class UsingTrait {
use t;
function bar() {
return $this->foo() + 1;
}
}
// this class imports but doesn't uses the trait
class UsingTrait {
use t;
function bar() {
return 1;
}
}
?>
There are some sneaky situations, where a trait falls into decay : for example, creating a method in the importing class, with the name of a trait class, will exclude the trait method, as the class method has priority. Other precedence rules may lead to the same effect.
See also Traits.
1.2.1294.1. Suggestions¶
Remove the trait from the class
Actually use the trait, at least in the importing class
Use conflict resolution to make the trait accessible
1.2.1294.2. Specs¶
Short name |
Traits/UnusedClassTrait |
Rulesets |
|
Exakat since |
2.1.1 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1295. Unused Traits¶
Those traits are not used in a class or another trait. They may be dead code.
<?php
// unused trait
trait unusedTrait { /**/ }
// used trait
trait tUsedInTrait { /**/ }
trait tUsedInClass {
use tUsedInTrait;
/**/
}
class foo {
use tUsedInClass;
}
?>
1.2.1295.1. Specs¶
Short name |
Traits/UnusedTrait |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1296. Used Trait¶
Mark a trait as being used by a class or another trait.
<?php
// One used trait
trait usedTrait {}
// One unused trait
trait unusedTrait {}
class foo {
use usedTrait;
}
?>
See also and Traits.
1.2.1296.1. Specs¶
Short name |
Traits/UsedTrait |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
Very high |
Available in |
1.2.1297. Useless Alias¶
It is not possible to declare an alias of a method with the same name.
PHP reports that Trait method f has not been applied, because there are collisions with other trait methods on x, which is a way to say that the alias will be in conflict with the method name.
When the method is the only one bearing a name, and being imported, there is no need to alias it. When the method is imported in several traits, the keyword insteadof is available to solve the conflict.
<?php
trait t {
function h() {}
}
class x {
use t {
// This is possible
t::f as g;
// This is not possible, as the alias is in conflict with itself
// alias are case insensitive
t::f as f;
}
}
?>
This code lints but doesn’t execute.
See also Conflict resolution.
1.2.1297.1. Suggestions¶
Remove the alias
Fix the alias or the origin method name
Switch to insteadof, and avoid as keyword
1.2.1297.2. Specs¶
Short name |
Traits/UselessAlias |
Rulesets |
|
Exakat since |
1.5.6 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.1298. Type Array Index¶
All literal index used in the code.
<?php
// index is an index. it is read
$array['index'] = 1;
// another_index and second_level are read
$array[] = $array['another_index']['second_level'];
// variables index are not reported
$array[$variable] = 1;
?>
1.2.1298.1. Specs¶
Short name |
Type/ArrayIndex |
Rulesets |
|
Exakat since |
1.0.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1299. Binary Glossary¶
List of all the integer values using the binary format.
<?php
$a = 0b10;
$b = 0B0101;
?>
See also Integer syntax.
1.2.1299.1. Specs¶
Short name |
Type/Binary |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
5.4+ |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Available in |
1.2.1300. All strings¶
Strings and heredocs in one place.
<?php
$string = 'string';
$query = <<<SQL
Heredoc
SQL;
?>
1.2.1300.1. Specs¶
Short name |
Type/CharString |
Rulesets |
|
Exakat since |
0.10.1 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1301. Continents¶
List of all the continents mentioned in the code.
1.2.1301.1. Specs¶
Short name |
Type/Continents |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1302. Duplicate Literal¶
Report literals that are repeated across the code. The minimum replication is 5, and is configurable with
maxDuplicate.
Repeated literals should be considered a prime candidate for constants.
Integer, reals and strings are considered here. Boolean, Null and Arrays are omitted. 0, 1, 2, 10 and the empty string are all omitted, as too common. This list of omitted constants may be configured with the ignoreList parameter : a comma separated list of values.
<?php
// array index are omitted
$x[3] = 'b';
// constanst are omitted
const X = 11;
define('Y', 'string')
// 0, 1, 2, 10 are omitted
$x = 0;
?>
1.2.1302.1. Suggestions¶
Create a constant and use it in place of the literal
Create a class constant and use it in place of the literal
Name |
Default |
Type |
Description |
minDuplicate |
15 |
integer |
Minimal number of duplication before the literal is reported. |
ignoreList |
0,1,2,10 |
array |
Common values that have to be ignored. Comma separated list. |
1.2.1302.2. Specs¶
Short name |
Type/DuplicateLiteral |
Rulesets |
|
Exakat since |
1.9.6 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1303. Email Addresses¶
List of all the email addresses that were found in the code.
Emails are detected with regex : [_A-Za-z0-9-]+(\\.[_A-Za-z0-9-]+)*`@ <https://www.php.net/manual/en/language.operators.errorcontrol.php>`_[A-Za-z0-9]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})
<?php
$email = 'contact@exakat.io';
?>
1.2.1303.1. Specs¶
Short name |
Type/Email |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1304. Incoming Variable Index Inventory¶
<?php
// x is collected
echo $_GET['x'];
// y is collected, but no z.
echo $_POST['y']['z'];
// a is not collected
echo $_ENV['s'];
?>
1.2.1304.1. Specs¶
Short name |
Type/GPCIndex |
Rulesets |
|
Exakat since |
1.0.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1305. Heredoc Delimiter Glossary¶
List of all the delimiters used to build a Heredoc string.
In the example below, EOD is the delimiter.
<?php
$a = <<<EOD
heredoc
EOD;
?>
See also Heredoc.
1.2.1305.1. Specs¶
Short name |
Type/Heredoc |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1306. Hexadecimal Glossary¶
List of all the integer values using the hexadecimal format.
<?php
$hexadecimal = 0x10;
$anotherHexadecimal =0XAF;
?>
See also Integer Syntax.
1.2.1306.1. Specs¶
Short name |
Type/Hexadecimal |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1307. Hexadecimal In String¶
Mark strings that may be confused with hexadecimal.
Until PHP 7.0, PHP recognizes hexadecimal numbers inside strings, and converts them accordingly.
PHP 7.0 and until 7.1, converts the string to 0, silently.
PHP 7.1 and later, emits a ‘A non-numeric value encountered’ warning, and convert the string to 0.
<?php
$a = '0x0030';
print $a + 1;
// Print 49
$c = '0x0030zyc';
print $c + 1;
// Print 49
$b = 'b0x0030';
print $b + 1;
// Print 0
?>
1.2.1307.1. Specs¶
Short name |
Type/HexadecimalString |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1308. Http Headers¶
List of HTTP headers use in the code.
<?php
header('Location: http://www.example.com/');
// Parseable headers are also reported
header('Location: http://www.example.com/');
// UnParseable headers are not reported
header('GarbagexxxxXXXXxxxGarbagexxxxXXXXxxx');
header($header);
?>
Those headers are mostly used with header() function to send to browser.
See also List of HTTP header fields.
1.2.1308.1. Specs¶
Short name |
Type/HttpHeader |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1309. HTTP Status Code¶
List of all the HTTP status codes mentioned in the code.
<?php
http_response_code(418);
header('HTTP/1.1 418 I\'m a teapot');
?>
See also List of HTTP status codes.
1.2.1309.1. Specs¶
Short name |
Type/HttpStatus |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1310. Integer Glossary¶
List of all the integer values.
<?php
$a = 1234; // integer
$a = 0123; // integer with octal representation
?>
See also Integers.
1.2.1310.1. Specs¶
Short name |
Type/Integer |
Rulesets |
none |
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
Very high |
Available in |
1.2.1311. Malformed Octal¶
Those numbers starts with a 0, so they are using the PHP octal convention. Therefore, one can’t use 8 or 9 figures in those numbers, as they don’t belong to the octal base. The resulting number will be truncated at the first erroneous figure. For example, 090 is actually 0, and 02689 is actually 22.
<?php
// A long way to write 0 in PHP 5
$a = 0890;
// A fatal error since PHP 7
?>
Also, note that very large octal, usually with more than 21 figures, will be turned into a real number and undergo a reduction in precision.
1.2.1311.1. Specs¶
Short name |
Type/MalformedOctal |
Rulesets |
CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, All |
Exakat since |
0.8.4 |
PHP Version |
With PHP 7.0 and older |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
Very high |
Available in |
1.2.1312. Md5 Strings¶
List of all the MD5 values hard coded in the application.
MD5 values are detected as hexadecimal strings, of length 32. No attempt at recognizing the origin value is made, so any such strings, including dummy ‘11111111111111111111111111111111’ are reported.
<?php
// 32
$a = '0cc175b9c0f1b6a831c399e269771111';
?>
See also MD5.
1.2.1312.1. Specs¶
Short name |
Type/Md5String |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1313. Mime Types¶
List of Mime Types that are mentioned in the code.
<?php
$mimeType = 'multipart/form-data';
$mimeType = 'image/jpeg';
$mimeType = 'application/zip';
header('Content-Type: '.$mimeType);
?>
1.2.1313.2. Specs¶
Short name |
Type/MimeType |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1314. No Real Comparison¶
Avoid comparing decimal numbers with ==, ===, !==, !=. Real numbers have an error margin which is random, and makes it very difficult to match even if the compared value is a literal.
PHP uses an internal representation in base 2 : any number difficult to represent with this base (like 0.1 or 0.7) will have a margin of error.
<?php
$a = 1/7;
$b = 2.0;
// 7 * $a is a real, not an integer
var_dump( 7 * $a === 1);
// rounding error leads to wrong comparison
var_dump( (0.1 + 0.7) * 10 == 8);
// although
var_dump( (0.1 + 0.7) * 10);
// displays 8
// precision formula to use with reals. Adapt 0.0001 to your precision needs
var_dump( abs(((0.1 + 0.7) * 10) - 8) < 0.0001);
?>
Use precision formulas with abs() to approximate values with a given precision, or avoid reals altogether.
See also Floating point numbers.
1.2.1314.1. Suggestions¶
Cast the values to integer before comparing
Compute the difference, and keep it below a threshold
Use the gmp or the bc extension to handle high precision numbers
Change the ‘precision’ directive of PHP : ini_set(‘precision’, 30) to make number larger
Multiply by a power of ten, before casting to integer for the comparison
Use floor(), ceil() or round() to compare the numbers, with a specific precision
1.2.1314.2. Specs¶
Short name |
Type/NoRealComparison |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
ClearPHP |
|
Examples |
|
Available in |
1.2.1315. Nowdoc Delimiter Glossary¶
List of all the delimiters used to build a Nowdoc string.
<?php
$nowdoc = <<<'EOD'
EOD;
?>
1.2.1315.1. Specs¶
Short name |
Type/Nowdoc |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1316. Octal Glossary¶
List of all the integer values using the octal format : an integer starting with an initial 0.
<?php
$a = 1234; // decimal number
$a = 0123; // octal number (equivalent to 83 decimal)
// silently valid for PHP 5.x
$a = 01283; // octal number (equivalent to 10 decimal)
?>
Putting an initial 0 is often innocuous, but in PHP, 0755 and 755 are not the same. The second is actually 1363 in octal, and will not provide the expected privileges.
See also Integers.
1.2.1316.1. Specs¶
Short name |
Type/Octal |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1317. Invalid Octal In String¶
Any octal sequence inside a string can’t be go 377. Those will be a fatal error at parsing time.
The check is applied to the string, starting with PHP 7.1. In PHP 7.0 and older, those sequences were silently adapted (modulo/% 400).
<?php
// A valid octal in a PHP string
echo \100; // @
// Emit a warning in PHP 7.1
//Octal escape sequence overflow \500 is greater than \377
echo \500; // @
// Silent conversion
echo \478; // 8
?>
1.2.1317.1. Suggestions¶
Use a double slash to avoid the sequence to be an octal sequence
Use a function call, such as decoct() to convert larger number to octal notation
See also and Integers.
1.2.1317.2. Specs¶
Short name |
Type/OctalInString |
Rulesets |
|
Exakat since |
0.9.1 |
PHP Version |
7.1- |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Available in |
1.2.1318. One Variable String¶
These strings only contains one variable or property or array.
<?php
$a = 0;
$b = "$a"; // This is a one-variable string
// Better way to write the above
$b = (string) $a;
// Alternatives :
$b2 = "$a[1]"; // This is a one-variable string
$b3 = "$a->b"; // This is a one-variable string
$c = "d";
$d = "D";
$b4 = "{$$c}";
$b5 = "{$a->foo()}";
?>
When the goal is to convert a variable to a string, it is recommended to use the type casting (string) operator : it is then clearer to understand the conversion. It is also marginally faster, though very little.
1.2.1318.1. Suggestions¶
Drop the surrounding string, keep the variable (or property…)
Include in the string any concatenation that comes unconditionaly after or before
Convert the variable to a string with the (type) operator
See also Strings and Type Juggling.
1.2.1318.2. Specs¶
Short name |
Type/OneVariableStrings |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
Very high |
Examples |
|
Available in |
1.2.1319. OpenSSL Ciphers Used¶
List of all the OpenSSL ciphers used in the code.
It is important to always use valid cipher modes for SSL. In case of non-existent cipher, the crypting or decrypting will not happen. Ciphers are marked as weak after their security is breached, and shall be removed from OpenSSL, and later, from PHP.
By reviewing this inventory, it is possible to detect forgotten ciphers, and fix them.
The full list of available ciphers for the PHP installation is available with the function openssl_get_cipher_methods().
<?php
// PHP documentation example, for PHP 7.1 and more recent
//$key should have been previously generated in a cryptographically safe way, like openssl_random_pseudo_bytes
$plaintext = message to be encrypted;
$cipher = aes-128-gcm;
if (in_array($cipher, openssl_get_cipher_methods()))
{
$ivlen = openssl_cipher_iv_length($cipher);
$iv = openssl_random_pseudo_bytes($ivlen);
$ciphertext = openssl_encrypt($plaintext, $cipher, $key, $options=0, $iv, $tag);
//store $cipher, $iv, and $tag for decryption later
$original_plaintext = openssl_decrypt($ciphertext, $cipher, $key, $options=0, $iv, $tag);
echo $original_plaintext.\n;
}
?>
See also openssl_encrypt() and OpennSSL [PHP manual].
1.2.1319.1. Specs¶
Short name |
Type/OpensslCipher |
Rulesets |
|
Exakat since |
2.1.1 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1320. Pack Format Inventory¶
<?php
$binarydata = "\x04\x00\xa0\x00";
$array = unpack("cn", $binarydata);
$initial = pack("cn", ...$array);
?>
1.2.1320.2. Specs¶
Short name |
Type/Pack |
Rulesets |
|
Exakat since |
1.5.0 |
PHP Version |
All |
Severity |
|
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1321. Path lists¶
List of all paths that were found in the code.
Path are identified with this regex : ^(.*/)([^/]*)\.\w+$. In particular, the directory delimiter is / : Windows delimiter \ are not detected.
<?php
// the first argument is recognized as an URL
fopen('/tmp/my/file.txt', 'r+');
// the string argument is recognized as an URL
$source = 'https://www.other-example.com/';
?>
URL are ignored when the protocol is present in the literal : http://www.example.com is not mistaken with a file.
See also Dir predefined constants and Supported Protocols and Wrappers.
1.2.1321.1. Specs¶
Short name |
Type/Path |
Rulesets |
|
Exakat since |
1.5.8 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1322. Perl Regex¶
List of all the Perl Regex (Pcre-style).
<?php
preg_match('/[abc]/', $haystack);
preg_replace('#[0-9A-Z]+#is', $y, $z);
?>
Regex are spotted when they are literals : dynamically built regex, (including /$x/) are not reported.
1.2.1322.1. Specs¶
Short name |
Type/Pcre |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1323. Internet Ports¶
List of all the Internet ports mentioned in the code.
Ports are recognized based on a internal database of port. They are found in Integers.
<?php
// 21 is the default port for FTP
$ftp = ftp_connect($host, 21, $timeout = 90);
?>
See also List of TCP and UDP port numbers.
1.2.1323.1. Specs¶
Short name |
Type/Ports |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1324. Printf Format Inventory¶
<?php
// Display a number with 2 digits
echo printf("%'.2d\n", 123);
?>
1.2.1324.1. Specs¶
Short name |
Type/Printf |
Rulesets |
|
Exakat since |
1.5.0 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1325. Protocol lists¶
List of all protocols that were found in the code.
From the manual : PHP comes with many built-in wrappers for various URL-style protocols for use with the filesystem functions such as fopen(), copy(), file_exists() and filesize().
<?php
// Example from the PHP manual, with the glob:// wrapper
// Loop over all *.php files in ext/spl/examples/ directory
// and print the filename and its size
$it = new DirectoryIterator(glob://ext/spl/examples/*.php);
foreach($it as $f) {
printf(%s: %.1FK\n, $f->getFilename(), $f->getSize()/1024);
}
?>
See also Supported Protocols and Wrappers.
1.2.1325.1. Specs¶
Short name |
Type/Protocols |
Rulesets |
|
Exakat since |
2.1.3 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1326. Regex Inventory¶
All regex used in the code. PHP has the PCRE extension that handles all regex : preg_match(), preg_replace(), etc.
<?php
// PCRE regex used with preg_match
preg_match('/[abc]+/', $string);
// Mbstring regex, in the arabic range
if(mb_ereg('[\x{0600}-\x{06FF}]', $text))
?>
mbstring regexes are also collected. Pre-PHP 7.0 POSIX regex are not listed.
- See also and
.
1.2.1326.1. Suggestions¶
See also preg_match(), `ext/mbstring <http://www.php.net/manual/en/book.mbstring.php> `_ and `ext/pcre <http://www.php.net/manual/en/book.pcre.php> `_.
1.2.1326.2. Specs¶
Short name |
Type/Regex |
Rulesets |
|
Exakat since |
0.12.14 |
PHP Version |
All |
Severity |
|
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1327. PHP Sapi¶
List of PHP SAPI mentioned in the code. When those SAPI are mentioned in strings, they are usually checked to take advantage of special characteristics. Check the code for portability.
<?php
require __DIR__.'/phpdbg.php';
$Phpdbg = new phpdbg();
?>
1.2.1327.1. Specs¶
Short name |
Type/Sapi |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1328. Shell commands¶
Shell commands, called from PHP.
Shell commands are detected with the italic quotes, and using shell_exec(), system(), exec() and proc_open().
<?php
// Shell command in a shell_exec() call
shell_exec('ls -1');
// Shell command with backtick operator
`ls -1 $path`;
?>
1.2.1328.1. Specs¶
Short name |
Type/Shellcommands |
Rulesets |
|
Exakat since |
1.9.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1329. Should Be Single Quote¶
Use single quote for simple strings.
Static content inside a string, that has no single quotes nor escape sequence (such as n or t), should be using single quote delimiter, instead of double quote.
<?php
$a = abc;
// This one is using a special sequence
$b = cde\n;
// This one is using two special sequences
$b = \x03\u{1F418};
?>
If you have too many of them, don’t loose your time switching them all. If you have a few of them, it may be good for consistence.
1.2.1329.1. Specs¶
Short name |
Type/ShouldBeSingleQuote |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
ClearPHP |
|
Available in |
1.2.1330. Should Typecast¶
When typecasting, it is better to use the casting operator, such as
(int)or(bool).
Functions such as intval() or settype() are always slower.
<?php
// Fast version
$int = (int) $X;
// Slow version
$int = intval($X);
// Convert to base 8 : can't use (int) for that
$int = intval($X, 8);
?>
This is a micro-optimisation, although such conversion may be use multiple times, leading to a larger performance increase.
Note that intval() may also be used to convert an integer to another base. Intval() called with 2 arguments are skipped by this rule.
1.2.1330.1. Suggestions¶
Use a typecast, instead of a functioncall.
1.2.1330.2. Specs¶
Short name |
Type/ShouldTypecast |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1331. Silently Cast Integer¶
Those are integer literals that are cast to a float when running PHP. They are too big for the current PHP version, and PHP resorts to cast them into a float, which has a much larger capacity but a lower precision.
Compare your literals to PHP_MAX_INT (typically 9223372036854775807) and PHP_MIN_INT (typically -9223372036854775808).
This applies to binary (0b10101…), octal (0123123…) and hexadecimal (0xfffff…) too.
<?php
echo 0b1010101101010110101011010101011010101011010101011010101011010111;
//6173123008118052203
echo 0b10101011010101101010110101010110101010110101010110101010110101111;
//1.2346246016236E+19
echo 0123123123123123123123;
//1498121094048818771
echo 01231231231231231231231;
//1.1984968752391E+19
echo 0x12309812311230;
//5119979279159856
echo 0x12309812311230fed;
//2.0971435127439E+19
echo 9223372036854775807; //PHP_MAX_INT
//9223372036854775807
echo 9223372036854775808;
9.2233720368548E+18
?>
See also Integer overflow.
1.2.1331.1. Suggestions¶
Make sure hexadecimal numbers have the right number of digits : generally, it is 15, but it may depends on your PHP version.
1.2.1331.2. Specs¶
Short name |
Type/SilentlyCastInteger |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1332. Similar Integers¶
This analysis reports all integer values that are expressed in different format.
<?php
// Three ways to write 10 (more available)
$a = 10;
$b = 012;
$x = 0xA;
// 7 is expressed in one way only
$d = 7;
$d = 7;
// Four ways to write 11 (more available)
$a = 11;
$b = 013;
$x = 0xB;
$x = -+-11;
// Expressions are not counted
?>
1.2.1332.1. Specs¶
Short name |
Type/SimilarIntegers |
Rulesets |
|
Exakat since |
1.9.0 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1333. Special Integers¶
Short and incomplete list of integers that may hold special values.
<?php
// 86400 is the number of seconds in a day
$day = 86400;
// 1400 is the number of minutes in a day
$day = 1440;
?>
The list includes powers of 2, duration in various units, factorial, ASCII codes and years.
1.2.1333.1. Specs¶
Short name |
Type/SpecialIntegers |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1334. SQL queries¶
SQL queries, detected in literal strings.
SQL queries are detected with keywords, inside literals or concatenations.
<?php
// SQL in a string
$query = 'SELECT name FROM users WHERE id = 1';
// SQL in a concatenation
$query = 'SELECT name FROM '.$table_users.' WHERE id = 1';
// SQL in a Heredoc
$query = <<<SQL
SELECT name FROM $table_users WHERE id = 1
SQL;
?>
1.2.1334.1. Specs¶
Short name |
Type/Sql |
Rulesets |
|
Exakat since |
0.10.1 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1335. String May Hold A Variable¶
Those strings looks like holding a variable.
Single quotes and Nowdoc syntax may include $ signs that are treated as literals, and not replaced with a variable value.
However, there are some potential variables in those strings, making it possible for an error : the variable was forgotten and will be published as such. It is worth checking the content and make sure those strings are not variables.
<?php
$a = 2;
// Explicit variable, but literal effect is needed
echo '$a is '.$a;
// One of the variable has been forgotten
echo '$a is $a';
// $CAD is not a variable, rather a currency unit
$total = 12;
echo $total.' $CAD';
// $CAD is not a variable, rather a currency unit
$total = 12;
// Here, $total has been forgotten
echo <<<'TEXT'
$total $CAD
TEXT;
?>
1.2.1335.1. Specs¶
Short name |
Type/StringHoldAVariable |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.1336. Interpolation¶
The following strings contain variables that are will be replaced. However, the following characters are ambiguous, and may lead to confusion.
<?php
class b {
public $b = 'c';
function __toString() { return __CLASS__; }
}
$x = array(1 => new B());
// -> after the $x[1] looks like a 2nd dereferencing, but it is not.
print $x[1]->b;
// displays : b->b
print {$x[1]->b};
// displays : c
?>
It is advised to add curly brackets around those structures to make them non-ambiguous.
See also Double quoted.
1.2.1336.1. Specs¶
Short name |
Type/StringInterpolation |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1337. Strings With Strange Space¶
An invisible space may be mistaken for a normal space.
However, PHP does straight comparisons, and may fail at recognizing. This analysis reports when it finds such strange spaces inside strings.
PHP doesn’t mistake space and tables for whitespace when tokenizing the code.
This analysis doesn’t report Unicode Codepoint Notation : those are visible in the code.
<?php
// PHP 7 notation,
$a = \u{3000};
$b = ;
// Displays false
var_dump($a === $b);
?>
See also Unicode spaces, and disallow irregular whitespace (no-irregular-whitespace).
1.2.1337.1. Suggestions¶
Replace the odd spaces with a normal space
If unsecable spaces are important for presentation, add them at the templating level.
1.2.1337.2. Specs¶
Short name |
Type/StringWithStrangeSpace |
Rulesets |
|
Exakat since |
0.11.0 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1338. Internet Domains¶
List all internet domain used
1.2.1338.1. Specs¶
Short name |
Type/UdpDomains |
Rulesets |
|
Exakat since |
1.9.6 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1339. Unicode Blocks¶
List of the Unicode blocks used in string literals.
This is the kind of characters that can be found in the applications strings.
<?php
$a = zoo;
$b = ఒ; // Telugu character
$b = \u{0C12}; Same as above
$b = 人; // Chinese Mandarin character
$b = \u{4EBA}; Same as above
?>
Note that Exakat only analyze PHP scripts : any translation available in a .po or external resource is not parsed and will not show.
See also Unicode block.
1.2.1339.1. Specs¶
Short name |
Type/UnicodeBlock |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1340. URL List¶
List of all the URL addresses that were found in the code.
<?php
// the first argument is recognized as an URL
ftp_connect('http://www.example.com/', $port, $timeout);
// the string argument is recognized as an URL
$source = 'https://www.other-example.com/';
?>
See also Uniform Resource Identifier.
1.2.1340.1. Specs¶
Short name |
Type/Url |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1341. Could Be Array Typehint¶
This rule spots arguments, properties or return values that may be labeled with the
arrayscalar typehint.
<?php
// $arg is used as an array in this function, so it may be typed : array
functions foo($arg) {
// the returned value is always an array, so this function might be typed as : array
return array($arg[3]);
}
?>
1.2.1341.2. Specs¶
Short name |
Typehints/CouldBeArray |
Rulesets |
|
Exakat since |
2.1.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1342. Could Be Boolean¶
Mark arguments and return types that can be set to boolean.
<?php
// Accept a boolean as input
function foo($b) {
// Returns a boolean
return $b === true;
}
?>
1.2.1342.1. Suggestions¶
Add bool typehint to the code.
1.2.1342.2. Specs¶
Short name |
Typehints/CouldBeBoolean |
Rulesets |
|
Exakat since |
2.1.2 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1343. Could Be CIT¶
Mark arguments and return types that can be set to a class, interface definition.
<?php
// Accept an object as input
function foo($b) {
// Returns new object
return new ($b->classname);
}
?>
1.2.1343.1. Suggestions¶
Add the class or interface typehint to the code.
1.2.1343.2. Specs¶
Short name |
Typehints/CouldBeCIT |
Rulesets |
|
Exakat since |
2.1.2 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1344. Could Be Callable¶
Mark arguments and return types that can be set to
callable.
The analysis also reports properties that could be ‘callable’, although PHP doesn’t allow that configuration.
<?php
// Accept a callable as input
function foo($b) {
// Returns value as return
return $b();
}
?>
Note that properties cannot be callable. It reports a compilation error.
See also Callbacks / callables.
1.2.1344.1. Suggestions¶
Add callable typehint to arguments or returntypes.
1.2.1344.2. Specs¶
Short name |
Typehints/CouldBeCallable |
Rulesets |
|
Exakat since |
2.1.2 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1345. Could Be Float¶
Mark arguments, properties and return types that can be set to
float.
<?php
// Accept an int as input
function foo($b) {
// Returns a float (cubic root of $b);
return pow($b, 1 / 3);
}
?>
1.2.1345.1. Suggestions¶
Add float typehint to the code.
1.2.1345.2. Specs¶
Short name |
Typehints/CouldBeFloat |
Rulesets |
CE, Typechecks, All |
Exakat since |
2.1.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1346. Could Be Generator¶
Return value may be typed
generator.
<?php
// Yield makes foo() a generator
function foo() {
yield 1;
// Returns an int
return $b + 8;
}
?>
1.2.1346.1. Suggestions¶
Add Generator typehint to the method.
1.2.1346.2. Specs¶
Short name |
Typehints/CouldBeGenerator |
Rulesets |
|
Exakat since |
2.2.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1347. Could Be Integer¶
Mark arguments, properties and return types that can be set to
int.
<?php
// Accept an int as input
function foo($b) {
// Returns an int
return $b + 8;
}
?>
1.2.1347.1. Suggestions¶
Add int typehint to the code.
1.2.1347.2. Specs¶
Short name |
Typehints/CouldBeInt |
Rulesets |
CE, Typechecks, All |
Exakat since |
2.1.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1348. Could Be Iterable¶
Mark arguments, properties and return types that can be set to
iterable.
<?php
// Accept an array or a traversable Object as input
function foo($b) {
foreach($b as $c) {
}
// Returns an array
return [$b];
}
?>
1.2.1348.1. Suggestions¶
Add iterable typehint to the code (PHP 8.0+).
1.2.1348.2. Specs¶
Short name |
Typehints/CouldBeIterable |
Rulesets |
|
Exakat since |
2.1.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1349. Could Be Null¶
Mark arguments and return types that can be null.
<?php
// Accept null as input, when used as third argument of file_get_contents
function foo($b) {
$s = file_get_contents(URL, false, $b);
// Returns a string
return shell_exec($s);
}
?>
1.2.1349.1. Suggestions¶
Add null typehint to the code (PHP 8.0+).
Add ? typehint to the code.
1.2.1349.2. Specs¶
Short name |
Typehints/CouldBeNull |
Rulesets |
CE, Typechecks, All |
Exakat since |
2.1.2 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1350. Could Be Parent¶
Mark arguments, return types and properties that can be set to
parent.
This analysis works when typehints have already been configured.
<?php
class x extends w {
// Accept a w object as input
function foo(w $b) : w {
// Returns a w object
return $b;
}
}
?>
1.2.1350.1. Suggestions¶
Add parent typehint to the code.
Add the literal class/type typehint to the code.
1.2.1350.2. Specs¶
Short name |
Typehints/CouldBeParent |
Rulesets |
|
Exakat since |
2.1.2 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1351. Could Be Self¶
Mark arguments, return types and properties that can be set to
self. This applies only to methods.
This analysis works when typehints have already been configured.
<?php
class x {
// Accept a x object as input
function foo(x $b) : x {
// Returns a x object
return $b;
}
}
?>
1.2.1351.1. Suggestions¶
Add self typehint to the code.
Add the literal class/type typehint to the code.
1.2.1351.2. Specs¶
Short name |
Typehints/CouldBeSelf |
Rulesets |
|
Exakat since |
2.1.2 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1352. Could Be String¶
Mark arguments and return types that can be set to string.
<?php
// Accept a string as input
function foo($a) {
// Returns a string
return $a . 'string';
}
?>
1.2.1352.1. Suggestions¶
Choose the string typehint, and add it to the code.
1.2.1352.2. Specs¶
Short name |
Typehints/CouldBeString |
Rulesets |
CE, Typechecks, All |
Exakat since |
2.1.2 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1353. Could Be Void¶
Mark return types that can be set to void.
<?php
// No return, this should be void.
function foo() {
++$a; // Not useful
}
?>
All abstract methods (in classes or in interfaces) are omitted here.
1.2.1353.1. Suggestions¶
Add the void typehint to the code.
1.2.1353.2. Specs¶
Short name |
Typehints/CouldBeVoid |
Rulesets |
|
Exakat since |
2.1.2 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1354. Could Not Type¶
Mark arguments, return types and properties that could not be typed.
Arguments, return types and properties that have no explicit typehint, and that could yield no guess from the following analysis, are deemed unable to receive a type.
Typehints/CouldBeCIT
Typehints/CouldBeString
Typehints/CouldBeArray
Typehints/CouldBeBoolean
Typehints/CouldBeVoid
Typehints/CouldBeCallable
mixed typehint, which acts as the universal typehint, is not processed here.
There are situation which cannot be typed, and legit : the example below is an illustration. array_fill is a native PHP example, where the second argument may be of any type. __get``and ``__set are also notoriously difficult to type, given the broad usage of arguments.
<?php
// Accepts any input, and returns any input
// This may be used, but not typed.
function foo($b) {
return $b;
}
?>
1.2.1354.1. Specs¶
Short name |
Typehints/CouldNotType |
Rulesets |
|
Exakat since |
2.1.2 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
Medium |
Available in |
1.2.1355. Missing Some Returntype¶
The specified typehints are not compatible with the returned values.
The code of the method may return other types, which are not specified and will lead to a PHP fatal error. It is the case for insufficient typehints, when a typehint is missing, or inconsistent typehints, when the method returns varied types.
<?php
// correct return typehint
function fooSN() : ?string {
return shell_exec('ls -hla');
}
// insufficient return typehint
// shell_exec() may return null or string. Here, only string in specified for fooS, and that may lead to a Fatal error
function fooS() : string {
return shell_exec('ls -hla');
}
// inconsistent return typehint
function bar() : int {
return rand(0, 10) ? 1 : b;
}
?>
The analysis reports a method when it finds other return types than the one expected. In the case of multiple typehints, as for the last example, the PHP code may require an upgrade to PHP 8.0.
1.2.1355.1. Suggestions¶
Update the typehint to accept more types
Update the code of the method to fit the expected returntype
1.2.1355.2. Specs¶
Short name |
Typehints/MissingReturntype |
Rulesets |
|
Exakat since |
2.1.7 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Available in |
1.2.1356. Assigned Twice¶
The same variable is assigned twice in the same function.
While this is possible and quite common, it is also a good practice to avoid changing a value from one literal to another. It is far better to assign the new value to
Incremental changes to a variables are not reported here.
<?php
function foo() {
// incremental changes of $a;
$a = 'a';
$a++;
$a = uppercase($a);
$b = 1;
$c = bar($b);
// B changed its purpose. Why not call it $d?
$b = array(1,2,3);
// This is some forgotten debug
$e = $config->getSomeList();
$e = array('OneElement');
}
?>
1.2.1356.1. Specs¶
Short name |
Variables/AssignedTwiceOrMore |
Rulesets |
|
Exakat since |
0.9.8 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1357. Blind Variables¶
Variables that are used in foreach or for structure, for their managing the loop itself.
<?php
foreach($array as $key => $value) {
// $key and $value are blind values
}
?>
1.2.1357.1. Specs¶
Short name |
Variables/Blind |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1358. Confusing Names¶
The following variables’s name are very close and may lead to confusion.
Variables are 3 letters long (at least). Variables names build with an extra s are omitted.
Variables may be scattered across the code, or close to each other.
Variables which differ only by case, or by punctuation or by numbers are reported here.
<?php
// Variable names with one letter difference
$fWScale = 1;
$fHScale = 1;
$fScale = 2;
$oFrame = 3;
$iFrame = new Foo();
$v2_norm = array();
$v1_norm = 'string';
$exept11 = 1;
$exept10 = 2;
$exept8 = 3;
// Variables that differ by punctation
$locale = 'fr';
$_locate = 'en';
// Variables that differ by numbers
$x11 = 'a';
$x12 = 'b';
// Variables that differ by numbers
$songMP3 = 'a';
$Songmp3 = 'b';
// This even looks like a typo
$privileges = 1;
$privilieges = true;
// This is not reported : Adding extra s is tolerated.
$rows[] = $row;
?>
See also How to pick bad function and variable names.
1.2.1358.1. Specs¶
Short name |
Variables/CloseNaming |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1359. Complex Dynamic Names¶
Avoid using expressions as names for variables or methods.
There are no place for checks or flow control, leading to any rogue value to be used as is. Besides, the expression is often overlooked, and not expected there : this makes the code less readable.
It is recommended to build the name in a separate variable, apply the usual checks for existence and validity, and then use the name.
<?php
$a = new foo();
// Code is more readable
$name = strolower($string);
if (!property_exists($a, $name)) {
throw new missingPropertyexception($name);
}
echo $a->$name;
// This is not check
echo $a->{strtolower($string)};
?>
This analysis only accept simple containers, such as variables, properties.
See also Dynamically Access PHP Object Properties with `$this <https://drupalize.me/blog/201508/dynamically-access-php-object-properties>`_.
1.2.1359.1. Suggestions¶
Extract the expression from the variable syntax, and make it a separate variable.
1.2.1359.2. Specs¶
Short name |
Variables/ComplexDynamicNames |
Rulesets |
|
Exakat since |
1.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1360. Constant Typo Looks Like A Variable¶
A constant bears the same name as a variable. This might be a typo.
When the constant doesn’t exist, PHP 8.0 yields a Fatal Error and stops execution. PHP 7.4 turns the undefined constant into its string equivalent.
<?php
// Get an object or null
$object = foo();
// PHP 8.0 stops here, with a Fatal Error
// PHP 7.4 makes this a string, and the condition is always true
if (!empty(object)) {
// In PHP 7.4, this is not protected by the condition, and may yield an error.
$object->doSomething();
}
?>
This analysis is case sensitive.
1.2.1360.1. Suggestions¶
Add a $ sign to the constant
Use a different name for the variable, or the constant
See also and .
1.2.1360.2. Specs¶
Short name |
Variables/ConstantTypo |
Rulesets |
|
Exakat since |
2.2.0 |
PHP Version |
With PHP 8.0 and older |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Medium |
Available in |
1.2.1361. Globals¶
Global variables.
<?php
// global via global keyword
global $a, $b;
// global via $GLOBALS variable
$GLOBALS['c'] = 1;
?>
1.2.1361.1. Specs¶
Short name |
Variables/Globals |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1362. Inconsistent Variable Usage¶
Those variables are used in various and inconsistent ways. It is difficult to understand if they are an array, an object or a scalar variable.
<?php
// $a is an array, then $b is a string.
$a = ['a', 'b', 'c'];
$b = implode('-', $a);
// $a is an array, then it is a string.
$a = ['a', 'b', 'c'];
$a = implode('-', $a);
?>
1.2.1362.1. Suggestions¶
Keep one type for each variable. This keeps the code readable.
Give different names to variables with different types.
1.2.1362.2. Specs¶
Short name |
Variables/InconsistentUsage |
Rulesets |
|
Exakat since |
1.6.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Examples |
|
Available in |
1.2.1363. Inherited Static Variable¶
<?php
// Code extracted from the RFC
class A {
public static function counter() {
static $i = 0;
return ++$i;
}
}
class B extends A {}
var_dump(A::counter()); // int(1)
var_dump(A::counter()); // int(2)
var_dump(B::counter()); // int(1)
var_dump(B::counter()); // int(2)
?>
See also PHP RFC: `Static variables in inherited methods <https://wiki.php.net/rfc/static_variable_inheritance>`_.
1.2.1363.1. Suggestions¶
Define the method in the child class to enforce the distinct behavior
Replace the static variable by a static property to make this PHP 8.1 ready
1.2.1363.2. Specs¶
Short name |
Variables/InheritedStaticVariable |
Rulesets |
|
Exakat since |
2.2.2 |
PHP Version |
With PHP 8.0 and older |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Medium |
Available in |
1.2.1364. Interface Arguments¶
Variables that are arguments in an interface.
<?php
interface i {
function interfaceMethod($interfaceArgument) ;
}
class foo extends i {
// Save function as above, but the variable is not reported
function interfaceMethod($notAnInterfaceArgument) {}
}
?>
1.2.1364.1. Specs¶
Short name |
Variables/InterfaceArguments |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1365. Local Globals¶
A global variable is used locally in a method.
Either the global keyword has been forgotten, or the local variable should be renamed in a less ambiguous manner.
Having both a global and a local variable with the same name is legit. PHP keeps the contexts separated, and it processes them independently.
However, in the mind of the coder, it is easy to mistake the local variable $x and the global variable $x. May they be given different meaning, and this is an error-prone situation.
It is recommended to keep the global variables’s name distinct from the local variables.
<?php
// This is actualy a global variable
$variable = 1;
$globalVariable = 2;
function foo() {
global $globalVariable2;
$variable = 4;
$localVariable = 3;
// This always displays 423, instead of 123
echo $variable .' ' . $globalVariable . ' ' . $localVariable;
}
?>
1.2.1365.1. Specs¶
Short name |
Variables/LocalGlobals |
Rulesets |
|
Exakat since |
1.1.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1366. Lost References¶
Either avoid references, or propagate them correctly.
When assigning a referenced variable with another reference, the initial reference is lost, while the intend was to transfer the content.
<?php
function foo(&$lostReference, &$keptReference)
{
$c = 'c';
// $lostReference was a reference to $bar, but now, it is a reference to $c
$lostReference =& $c;
// $keptReference was a reference to $bar : it is still now, though it contains the actual value of $c now
$keptReference = $c;
}
$bar = 'bar';
$bar2 = 'bar';
foo($bar, $bar2);
//displays bar c, instead of bar bar
print $bar. ' '.$bar2;
?>
Do not reassign a reference with another reference. Assign new content to the reference to change its value.
1.2.1366.1. Suggestions¶
Always assign new value to an referenced argument, and don’t reassign a new reference
1.2.1366.2. Specs¶
Short name |
Variables/LostReferences |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1367. No Static Variable In A Method¶
Refactor static variables into properties.
Inside a class, it is recommended to use the class properties, static or not, to hold values between calls to the method. Inside a function, or a closure, no such container is available, so static variables may be useful. Although, a refactoring to a class is also recommended here.
Properties have clear definitions, and are less suprising than static variables.
<?php
class barbar {
function foo() {
static $counter = 0;
// count the number of calls of this method
return ++$counter;
}
}
class bar {
static $counter = 0;
function foo() {
// count the number of calls of this method
return ++self::$counter;
}
}
?>
The static variable is easier to refactor as a static property. It is also possible to refactor it as a property, although it may impact the behavior of the previous code, or require extra work.
1.2.1367.1. Suggestions¶
Refactor the variable into a static property
Refactor the variable into a property and then use dependency injection
1.2.1367.2. Specs¶
Short name |
Variables/NoStaticVarInMethod |
Rulesets |
|
Exakat since |
2.2.1 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Available in |
1.2.1368. Overwriting Variable¶
Replacing the content of a variable by something different is prone to errors. For example, it is not obvious if the $text variable is plain text or HTML text.
<?php
// Confusing
$text = htmlentities($text);
// Better
$textHTML = htmlentities($text);
?>
Besides, it is possible that the source is needed later, for extra processing.
Note that accumulators, like += .= or [] etc., that are meant to collect lots of values with consistent type are OK.
1.2.1368.1. Specs¶
Short name |
Variables/Overwriting |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1369. Overwritten Literals¶
The same variable is assigned a literal twice. It is possible that one of the assignation is too much.
This analysis doesn’t take into account the distance between two assignations : it may report false positives when the variable is actually used for several purposes, and, as such, assigned twice with different values.
<?php
function foo() {
// Two assignations in a short sequence : one is too many.
$a = 1;
$a = 2;
for($i = 0; $i < 10; $i++) {
$a += $i;
}
$b = $a;
// New assignation. $a is now used as an array.
$a = array(0);
}
?>
1.2.1369.1. Specs¶
Short name |
Variables/OverwrittenLiterals |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Available in |
1.2.1370. PHP5 Indirect Variable Expression¶
Indirect variable expressions changes between PHP 5 an 7.
The following structures are evaluated differently in PHP 5 and 7. It is recommended to review them or switch to a less ambiguous syntax.
<?php
// PHP 7
$foo = 'bar';
$bar['bar']['baz'] = 'foobarbarbaz';
echo $$foo['bar']['baz'];
echo ($$foo)['bar']['baz'];
// PHP 5
$foo['bar']['baz'] = 'bar';
$bar = 'foobarbazbar';
echo $$foo['bar']['baz'];
echo ${$foo['bar']['baz']};
?>
See Backward incompatible changes PHP 7.0
Expression |
PHP 5 interpretation |
PHP 7 interpretation |
$$foo[‘bar’][‘baz’] $foo->$bar[‘baz’] $foo->$bar[‘baz’]() Foo::$bar[‘baz’]() |
${$foo[‘bar’][‘baz’]} $foo->{$bar[‘baz’]} $foo->{$bar[‘baz’]}() Foo::{$bar[‘baz’]}() |
($$foo)[‘bar’][‘baz’] ($foo->$bar)[‘baz’] ($foo->$bar)[‘baz’]() (Foo::$bar)[‘baz’]() |
1.2.1370.1. Suggestions¶
Avoid using complex expressions, mixing
$$\,[0]and->in the same expressionAdd curly braces {} to ensure that the precedence is the same between PHP 5 and 7. For example,
$$vbecomes${$v}
1.2.1370.2. Specs¶
Short name |
Variables/Php5IndirectExpression |
Rulesets |
CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, All |
Exakat since |
0.8.4 |
PHP Version |
7.0- |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1371. Php 7 Indirect Expression¶
Those are variable indirect expressions that are interpreted differently in PHP 5 and PHP 7.
You should check them so they don’t behave strangely.
<?php
// Ambiguous expression :
$b = $$foo['bar']['baz'];
echo $b;
$foo = array('bar' => array('baz' => 'bat'));
$bat = 'PHP 5.6';
// In PHP 5, the expression above means :
$b = $\{$foo['bar']['baz']};
$b = 'PHP 5.6';
$foo = 'a';
$a = array('bar' => array('baz' => 'bat'));
// In PHP 7, the expression above means :
$b = ($$foo)['bar']['baz'];
$b = 'bat';
?>
See also Changes to variable handling.
1.2.1371.1. Suggestions¶
Avoid using complex expressions, mixing $$, [0] and -> in the same expression
Add curly braces {} to ensure that the precedence is the same between PHP 5 and 7. For example,
$$vbecomes${$v}
1.2.1371.2. Specs¶
Short name |
Variables/Php7IndirectExpression |
Rulesets |
CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, CompatibilityPHP70, All |
Exakat since |
0.8.4 |
PHP Version |
7.0+ |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1372. Real Variables¶
Inventory of real variables. Global, Static and property declarations are skipped here.
<?php
$realVariable = 1;
class foo {
private $property; // not a variable
private function bar() {
global $global; // not a variable
static $static; // not a variable
}
}
?>
This is a refined version of a search on T_VARIABLE token.
1.2.1372.1. Specs¶
Short name |
Variables/RealVariables |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1373. Variable References¶
Variables that are references.
<?php
$a = '1'; // not a reference
$b = &$a; // a reference
?>
See also References.
1.2.1373.1. Specs¶
Short name |
Variables/References |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1374. Self-Transforming Variables¶
Variables that are assigned to themselves after transformation.
<?php
$s = strtolower($s);
// filtering one element AND dropping all that not 1
$a = array_filter('foo', $a[1]);
$o->m = foo($o->m);
?>
1.2.1374.1. Suggestions¶
Try to use new variables to hold new values.
1.2.1374.2. Specs¶
Short name |
Variables/SelfTransform |
Rulesets |
|
Exakat since |
1.7.0 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1375. Static Variables¶
<?php
function foo() {
// static variable
static $count = 0;
echo ++$count;
}
class bar {
// This is not a static variable :
// it is a static property
static $property = 1;
}
?>
1.2.1375.1. Specs¶
Short name |
Variables/StaticVariables |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Available in |
1.2.1376. Strange Name For Variables¶
Variables with strange names. They might be a typo, or bear strange patterns.
Any variable with three identical letter in a row are considered as strange. 2 letters in a row is classic, and while three letters may happen, it is rare enough.
A list of classic typo is also used to find such variables.
This analysis is case-sensitive.
<?php
class foo {
function bar() {
// Strange name $tihs
return $tihs;
}
function barbar() {
// variables with blocks of 3 times the same character are reported
// Based on Alexandre Joly's tweet
$aaa = $bab + $www;
}
}
?>
See also #QuandLeDevALaFleme.
1.2.1376.1. Suggestions¶
Fix the name of the variable
Rename the variable to something better
Drop the variable
1.2.1376.2. Specs¶
Short name |
Variables/StrangeName |
Rulesets |
|
Exakat since |
0.10.5 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Examples |
|
Available in |
1.2.1377. Environment Variables¶
Environment variables are used to interact with the hosting system.
They often provides configuration parameter that are set by the host of the application to be used. That way, information is not hardcoded in the application, and may be changed at production.
<?php
//ENVIRONMENT set the production context
if (getenv('ENVIRONMENT') === 'Production') {
$sshKey = getenv('HOST_KEY');
} elseif (getenv('ENVIRONMENT') === 'Developper') {
$sshKey = 'NO KEY';
} else {
header('No website here.');
die();
}
?>
See also $_ENV.
1.2.1377.1. Specs¶
Short name |
Variables/UncommonEnvVar |
Rulesets |
|
Exakat since |
1.0.5 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
Medium |
Available in |
1.2.1378. Undefined Constant Name¶
When using the `` syntax for variable, the name used must be a defined constant. It is not a simple string, like ‘x’, it is an actual constant name.
Interestingly, it is possible to use a qualified name within ``, full or partial. PHP will lint such code, and will collect the value of the constant immediately. Since there is no fallback mechanism for fully qualified names, this ends with a Fatal error.
<?php
const x = a;
$a = Hello;
// Display 'Hello' -> $a -> Hello
echo ;
// Yield a PHP Warning
// Use of undefined constant y - assumed 'y' (this will throw an Error in a future version of PHP)
echo ;
// Yield a PHP Fatal error as PHP first checks that the constant exists
//Undefined constant 'y'
echo ;
?>
1.2.1378.1. Suggestions¶
Define the constant
Turn the dynamic syntax into a normal variable syntax
Use a fully qualified name (at least one ) to turn this syntax into a Fatal error when the constant is not found. This doesn’t fix the problem, but may make it more obvious during the diagnostic.
1.2.1378.2. Specs¶
Short name |
Variables/UndefinedConstantName |
Rulesets |
|
Exakat since |
2.1.1 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1379. Undefined Variable¶
Variable that is used before any creation.
It is recommended to use a default value for every variable used. When not specified, the default value is set to NULL by PHP.
<?php
// Adapted from the PHP manual
$var = 'Bob';
$Var = 'Joe';
// The following line may emit a warning : Undefined variable: $undefined
echo $var, $Var, $undefined; // outputs Bob, Joe,
?>
Variable may be created in various ways : assignation, arguments, foreach blind variables, static and global variables.
This analysis doesn’t handle dynamic variables, such as $$x. It also doesn’t handle variables outside a method or function.
1.2.1379.1. Suggestions¶
Remove the expression that is using the undefined variable
Fix the variable name
Define the variable by assigning a value to it, before using it
See also and Variable basics.
1.2.1379.2. Specs¶
Short name |
Variables/UndefinedVariable |
Rulesets |
|
Exakat since |
1.4.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1380. Single Use Variables¶
Variables that are written, then read. Only used once.
Single-use variables may be trimmed down, and the initial expression may be used instead.
Single-use variables may improve readability, when the final expression grows too much with the extra expression.
<?php
function foo($d) {
$a = 1; // $a is used twice
$b = $a + 2; // $b is used once
$c = $a + $b + $d; // $c is also used once
// $d is an argument, so it's OK.
retrun $c;
}
?>
1.2.1380.1. Suggestions¶
Merge the two expressions into one larger
Make a second use of the variable
1.2.1380.2. Specs¶
Short name |
Variables/UniqueUsage |
Rulesets |
|
Exakat since |
1.3.0 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1381. Variables With Long Names¶
VariablesLong collect all variables with more than 20 characters longs.
<?php
// Quite a long variable name
$There_is nothing_wrong_with_long_variable_names_They_tend_to_be_rare_and_that_make_them_noteworthy = 1;
?>
There is nothing wrong with long variable names. They tend to be rare, and that make them noteworthy.
See also Basics.
Name |
Default |
Type |
Description |
variableLength |
20 |
integer |
Minimum size of a long variable name, including the initial $. |
1.2.1381.1. Specs¶
Short name |
Variables/VariableLong |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1382. Non Ascii Variables¶
PHP allows certain characters in variable names. The variable name must only include letters, figures, underscores and ASCII characters from 128 to 255.
In practice, letters outside the scope of a-zA-Z0-9 are rare, and require more care when editing the code or passing it from OS to OS.
<?php
class 人 {
// An actual working class in PHP.
public function __construct() {
echo __CLASS__;
}
}
$人民 = new 人();
?>
See also Variables.
1.2.1382.1. Suggestions¶
Make sure those special chars have actual meaning.
1.2.1382.2. Specs¶
Short name |
Variables/VariableNonascii |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Examples |
|
Available in |
1.2.1383. Variables With One Letter Names¶
Variables with one letter name are the shortest name for variables. They also bear very little meaning : what does contain the variable
$w?
Some one-letter variables have meaning : $x and $y for coordinates, $i, $j, $k for blind variables. Others tend to be an easy way to give a name to a variable, without thinking too hard a good name.
<?php
// $a is reported as a one-letter variable
$a = 0;
// $i is considered a false positive.
for($i = 0; $i < 10; ++$i) {
$a += doSomething($i);
}
?>
See also Using single characters for variable names in loops/exceptions and Single Letter Variable Names Still Considered Harmful.
1.2.1383.1. Suggestions¶
Make the variable more meaningful, with full words
1.2.1383.2. Specs¶
Short name |
Variables/VariableOneLetter |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
Very high |
Available in |
1.2.1384. PHP Variables¶
This is the list of PHP predefined variables that are used in the application.
<?php
// Reading an incoming email, with sanitation
$email = filter_var($_GET['email'], FILTER_SANITIZE_EMAIL);
?>
The web variables ($\_GET, $\_COOKIE, $\_FILES) are quite commonly used, though sometimes replaced by some special accessors. Others are rarely used.
See also and Predefined Variables.
1.2.1384.1. Specs¶
Short name |
Variables/VariablePhp |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
Very high |
Available in |
1.2.1385. All Uppercase Variables¶
Usually, global variables are all in uppercase, so as to differentiate them easily. Though, this is not always the case, with examples like $argc, $argv or $http_response_header.
When using custom variables, try to use lowercase $variables, $camelCase, $sturdyCase or $snake_case.
<?php
// PHP super global, also identified by the initial _
$localVariable = $_POST;
// PHP globals
$localVariable = $GLOBALS['HTTPS'];
?>
See also Predefined Variables.
1.2.1385.1. Specs¶
Short name |
Variables/VariableUppercase |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1386. Used Once Variables¶
This is the list of used once variables.
<?php
// The variables below never appear again in the code
$writtenOnce = 1;
foo($readOnce);
?>
Such variables are useless. Variables must be used at least twice : once for writing, once for reading, at least. It is recommended to remove them.
In special situations, variables may be used once :
PHP predefined variables, as they are already initialized. They are omitted in this analyze.
Interface function’s arguments, since the function has no body; They are omitted in this analyze.
Dynamically created variables ($$x, ${$this->y} or also using extract), as they are runtime values and can’t be determined at static code time. They are reported for manual review.
Dynamically included files will provide in-scope extra variables.
This rule counts variables at the application level, and not at a method scope level.
1.2.1386.1. Suggestions¶
Remove the variable
Fix the name of variable
Use the variable a second time, at least
1.2.1386.2. Specs¶
Short name |
Variables/VariableUsedOnce |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Instant (5 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1387. Used Once Variables (In Scope)¶
This is the list of used once variables, scope by scope. Those variables are used once in a function, a method, a class or a namespace. In any case, this means the variable is read or written, while it should be used at least twice.
Static and global variables are omitted here : they may be used multiple times by having the method being called multiple times.
<?php
function foo() {
// The variables below never appear twice, inside foo()
$writtenOnce = 1;
foo($readOnce);
// They do appear again in other functions, or in global space.
}
function bar() {
$writtenOnce = 1;
foo($readOnce);
}
?>
1.2.1387.1. Suggestions¶
Remove the variable
Fix the name of variable
Use the variable a second time in the current scope, at least
See also and .
1.2.1387.2. Specs¶
Short name |
Variables/VariableUsedOnceByContext |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Examples |
|
Available in |
1.2.1388. Variable Variables¶
A variable variable takes the value of a variable and treats that as the name of a variable.
PHP has the ability to dynamically use a variable.
<?php
// Normal variable
$a = 'b';
$b = 'c';
// Variable variable
$d = $$b;
// Variable variable in string
$d = "$\{$b\}";
?>
They are also called ‘dynamic variable’.
See also Variable variables.
1.2.1388.1. Specs¶
Short name |
Variables/VariableVariables |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1389. Written Only Variables¶
Those variables are being written, but never read. This way, they are useless and should be removed, or read at some point.
<?php
// $a is used multiple times, but never read
$a = 'a';
$a .= 'b';
$b = 3;
//$b is actually read once
$a .= $b + 3;
?>
1.2.1389.1. Suggestions¶
Check that variables are written AND read in each context
Remove variables that are only read
Use the variable that are only read
1.2.1389.2. Specs¶
Short name |
Variables/WrittenOnlyVariable |
Rulesets |
|
Exakat since |
0.8.4 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
ClearPHP |
|
Examples |
|
Available in |
1.2.1390. Codeigniter usage¶
This analysis reports usage of the Codeigniter framework.
<?php
// A code igniter controller
class Blog extends CI_Controller {
public function index()
{
echo 'Hello World!';
}
}
?>
See also Codeigniter.
1.2.1390.1. Specs¶
Short name |
Vendors/Codeigniter |
Rulesets |
|
Exakat since |
0.11.8 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1391. Concrete usage¶
This analysis reports usage of the Concrete 5 framework.
<?php
namespace Application\Controller\PageType;
use Concrete\Core\Page\Controller\PageTypeController;
class BlogEntry extends PageTypeController
{
public function view()
{
}
}
?>
See also Concrete 5.
1.2.1391.1. Specs¶
Short name |
Vendors/Concrete5 |
Rulesets |
|
Exakat since |
1.9.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1392. Drupal Usage¶
This analysis reports usage of the Drupal CMS. The report is based on the usage of Drupal namespace.
<?php
namespace Drupal\example\Controller;
use Drupal\Core\Controller\ControllerBase;
/**
* An example controller.
*/
class ExampleController extends ControllerBase {
/**
* {@inheritdoc}
*/
public function content() {
$build = array(
'#type' => 'markup',
'#markup' => t('Hello World!'),
);
return $build;
}
}
?>
See also Drupal.
1.2.1392.1. Specs¶
Short name |
Vendors/Drupal |
Rulesets |
|
Exakat since |
1.0.3 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1393. Ez cms usage¶
This analysis reports usage of the Ez cms.
<?php
namespace My\Bundle\With\Controller;
use eZ\Bundle\EzPublishCoreBundle\Controller;
use Symfony\Component\HttpFoundation\Request;
class DemoController extends Controller {
public function demoCreateContentAction(Request $request) {
//
}
}
?>
See also Ez.
1.2.1393.1. Specs¶
Short name |
Vendors/Ez |
Rulesets |
|
Exakat since |
0.11.8 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1394. FuelPHP Usage¶
This analysis reports usage of the Fuel PHP Framework. The report is based on the usage of Fuel namespace.
<?php
// file located in APPPATH/classes/presenter.php
class Presenter extends \Fuel\Core\Presenter
{
// namespace prefix
protected static $ns_prefix = 'Presenter\';
}
?>
See also FuelPHP.
1.2.1394.1. Specs¶
Short name |
Vendors/Fuel |
Rulesets |
|
Exakat since |
1.0.3 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1395. Joomla usage¶
This analysis reports usage of the Joomla CMS.
<?php
// no direct access
defined('_JEXEC') or die('Restricted access');
jimport('joomla.application.component.controller');
JLoader::import('KBIntegrator', JPATH_PLUGINS . DS . 'kbi');
class MyController extends JController {
function display($message) {
echo $message;
}
}
?>
See also Joomla.
1.2.1395.1. Specs¶
Short name |
Vendors/Joomla |
Rulesets |
|
Exakat since |
0.11.8 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1396. Laravel usage¶
This analysis reports usage of the Laravel framework.
<?php
namespace App\Http\Controllers;
use App\User;
use App\Http\Controllers\Controller;
class UserController extends Controller
{
/**
* Show the profile for the given user.
*
* @param int $id
* @return Response
*/
public function show($id)
{
return view('user.profile', ['user' => User::findOrFail($id)]);
}
}
?>
See also Laravel.
1.2.1396.1. Specs¶
Short name |
Vendors/Laravel |
Rulesets |
|
Exakat since |
0.11.8 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1397. Phalcon Usage¶
This analysis reports usage of the Phalcon Framework. The report is based on the usage of Phalcon namespace, which may be provided by PHP code inclusion or the PHP extension.
<?php
use Phalcon\Mvc\Application;
// Register autoloaders
// Register services
// Handle the request
$application = new Application($di);
try {
$response = $application->handle();
$response->send();
} catch (\Exception $e) {
echo 'Exception: ', $e->getMessage();
}
?>
See also Phalcon.
1.2.1397.1. Specs¶
Short name |
Vendors/Phalcon |
Rulesets |
|
Exakat since |
1.0.3 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1398. Symfony usage¶
This analysis reports usage of the Symfony framework.
<?php
// src/AppBundle/Controller/LuckyController.php
namespace AppBundle\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\HttpFoundation\Response;
class LuckyController
{
/**
* @Route(/lucky/number)
*/
public function numberAction()
{
$number = mt_rand(0, 100);
return new Response(
'<html><body>Lucky number: '.$number.'</body></html>'
);
}
}
?>
See also Symfony.
1.2.1398.1. Specs¶
Short name |
Vendors/Symfony |
Rulesets |
|
Exakat since |
0.11.8 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1399. Typo 3 usage¶
This analysis reports usage of the Typo 3 CMS.
<?php
namespace MyVendor\SjrOffers\Controller;
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
class OfferController extends ActionController
{
// Action methods will be following here
}
?>
See also Typo3.
1.2.1399.1. Specs¶
Short name |
Vendors/Typo3 |
Rulesets |
|
Exakat since |
1.9.9 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1400. Wordpress usage¶
This analysis reports usage of the Wordpress platform.
<?php
//Usage of the WP_http class from Wordpress
$rags = array(
'x' => '1',
'y' => '2'
);
$url = 'http://www.example.com/';
$request = new WP_Http();
$result = $request->request( $url, array( 'method' => 'POST', 'body' => $body) );
?>
See also Wordpress.
1.2.1400.1. Specs¶
Short name |
Vendors/Wordpress |
Rulesets |
|
Exakat since |
0.11.8 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1401. Yii usage¶
This analysis reports usage of the Yii framework.
<?php
// A Yii controller
class SiteController extends CController
{
public function actionIndex()
{
// ...
}
public function actionContact()
{
// ...
}
}
?>
See also Yii.
1.2.1401.1. Specs¶
Short name |
Vendors/Yii |
Rulesets |
|
Exakat since |
0.11.8 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1402. First Class Callable¶
A syntax using ellipsis was introduced to make it easy to make a method into a callable.
<?php
// Using ellipsis as the only argument
$a = $object->method(...);
// Old style equivalent
$a = array($object, 'method');
// calling the closure.
$a();
?>
See also PHP RFC: First-class callable syntax.
1.2.1402.1. Specs¶
Short name |
Php/FirstClassCallable |
Rulesets |
|
Exakat since |
2.3.0 |
PHP Version |
With PHP 8.1 and more recent |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Available in |
1.2.1403. Mixed Keyword¶
Never becomes a PHP keyword. It is used for typing functions which never returns anything (either dies or throw an exception).
It should be avoided in classes, traits and interfaces. Methods, anonymous classes (sic), namespaces and functions are OK.
Setting a never class in a namespaces doesn’t make it legit.
<?php
// This is OK
function never() { }
// This is no OK
class never { }
?>
See also mixed.
1.2.1403.1. Suggestions¶
Rename the classes, traits and interfaces with a different name.
1.2.1403.2. Specs¶
Short name |
Php/MixedKeyword |
Rulesets |
none |
Exakat since |
2.3.0 |
PHP Version |
With PHP 8.0 and older |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
Very high |
Available in |
1.2.1404. Mixed Typehint Usage¶
Usage of the mixed typehint.
<?php
function foo() : mixed {
switch(rand(0, 3)) {
case 0:
return false;
case 1:
return 'a';
case 2:
return [];
default:
return null;
}
}
?>
See also Type declarations.
1.2.1404.1. Specs¶
Short name |
Php/MixedUsage |
Rulesets |
|
Exakat since |
2.3.0 |
PHP Version |
With PHP 8.1 and more recent |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Available in |
1.2.1405. Named Parameter Usage¶
Named parameters is a way to call a method, by specifying the name of the argument, instead of their position order.
Named parameters works for both custom methods and PHP native functions.
<?php
// named parameters
foo(a : 1, b : 2);
foo(b : 2, a : 1);
// positional parameters
foo(1, 2);
function foo($a, $b) { }
?>
1.2.1405.1. Specs¶
Short name |
Php/NamedParameterUsage |
Rulesets |
Appinfo, CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, CompatibilityPHP70, CompatibilityPHP71, CompatibilityPHP72, CompatibilityPHP73, CompatibilityPHP74, All |
Exakat since |
2.3.0 |
PHP Version |
With PHP 8.0 and more recent |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Available in |
1.2.1406. Never Keyword¶
Never becomes a PHP keyword. It is used for typing functions which never returns anything (either dies or throw an exception).
It should be avoided in classes, traits and interfaces. Methods, anonymous classes (sic), namespaces and functions are OK.
Setting a never class in a namespaces doesn’t make it legit.
<?php
// This is OK
function never() { }
// This is no OK
class never { }
?>
See also PHP RFC: noreturn type.
1.2.1406.1. Suggestions¶
Rename the classes, traits and interfaces with a different name.
1.2.1406.2. Specs¶
Short name |
Php/NeverKeyword |
Rulesets |
|
Exakat since |
2.3.0 |
PHP Version |
With PHP 8.1 and older |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
Very high |
Available in |
1.2.1407. New Functions In PHP 8.1¶
New functions are added to new PHP version.
The following functions are now native functions in PHP 8.1. It is compulsory to rename any custom function that was created in older versions. One alternative is to move the function to a custom namespace, and update the use list at the beginning of the script.
array_is_list()
enum_exists()
fsync()
fdatasync()
imagecreatefromavif()
imageavif()
mysqli_fetch_column()
sodium_crypto_core_ristretto255_add()
sodium_crypto_core_ristretto255_from_hash()
sodium_crypto_core_ristretto255_is_valid_point()
sodium_crypto_core_ristretto255_random()
sodium_crypto_core_ristretto255_scalar_add()
sodium_crypto_core_ristretto255_scalar_complement()
sodium_crypto_core_ristretto255_scalar_invert()
sodium_crypto_core_ristretto255_scalar_mul()
sodium_crypto_core_ristretto255_scalar_negate()
sodium_crypto_core_ristretto255_scalar_random()
sodium_crypto_core_ristretto255_scalar_reduce()
sodium_crypto_core_ristretto255_scalar_sub()
sodium_crypto_core_ristretto255_sub()
sodium_crypto_scalarmult_ristretto255()
sodium_crypto_scalarmult_ristretto255_base()
sodium_crypto_stream_xchacha20()
sodium_crypto_stream_xchacha20_keygen()
sodium_crypto_stream_xchacha20_xor()
Note : At the moment of writing, all links to the manual are not working.
1.2.1407.1. Specs¶
Short name |
Php/Php81NewFunctions |
Rulesets |
|
Exakat since |
2.3.0 |
PHP Version |
With PHP 8.1 and older |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1408. PHP 8.1 Removed Functions¶
The following PHP native functions were deprecated in PHP 8.1, and will be removed in PHP 9.0.
1.2.1408.1. Suggestions¶
Avoid using those functions anymore
1.2.1408.2. Specs¶
Short name |
Php/Php81RemovedFunctions |
Rulesets |
|
Exakat since |
2.3.0 |
PHP Version |
8.1- |
PHP deprecated |
With PHP 8.1 and more recent |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
High |
Available in |
1.2.1409. False To Array Conversion¶
The auto vivification of false is deprecated. This feature is the automagical conversion of a boolean into an array, if needed.
<?php
$a = false;
//valid in PHP
$a[3] = 1;
?>
Until PHP 8.1, this was possible. This feature is deprecated in PHP 8.1, and will be removed in PHP 9.0.
1.2.1409.1. Suggestions¶
Change the typehints from bool or false to array
Validate the type returned values of an functioncall before using it
1.2.1409.2. Specs¶
Short name |
Php/FalseToArray |
Rulesets |
Analyze, CompatibilityPHP81, LintButWontExec, All, CompatibilityPHP82 |
Exakat since |
2.3.0 |
PHP Version |
All |
PHP deprecated |
8.1 |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1410. Float Conversion As Index¶
Only integers and strings are possible types when used for array index. Until PHP 8.1, floats were converted to integer by truncation. Since PHP 8.1, a deprecated message is emited.
The implicit conversion of float to int which leads to a loss in precision is now deprecated. This affects array keys, int type declarations in coercive mode, and operators working on ints.
<?php
$a = [];
$a[15.5]; // deprecated, as key value loses the 0.5 component
$a[15.0]; // ok, as 15.0 == 15
?>
See also Implicit incompatible float to int conversions.
1.2.1410.1. Specs¶
Short name |
Arrays/FloatConversionAsIndex |
Rulesets |
|
Exakat since |
2.3.1 |
PHP Version |
With PHP 8.1 and more recent |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Medium |
Available in |
1.2.1411. Nested Attributes¶
Nested attribute are attribute in attributes.
<?php
// Extracted from PHP 8.1 addendum (https://www.php.net/releases/8.1/en.php#new_in_initializers)
class User
{
#[\Assert\All(
new \Assert\NotNull,
new \Assert\Length(min: 6))
]
public string $name = '';
}
?>
Nested attributes are not available in PHP 8.0 and older. It is reported as an invalid constant expression. See also PHP RFC: New in initializers and New initializers.
1.2.1411.1. Specs¶
Short name |
Attributes/NestedAttributes |
Rulesets |
Appinfo, CompatibilityPHP73, CompatibilityPHP74, CompatibilityPHP80, All |
Exakat since |
2.3.1 |
PHP Version |
With PHP 8.1 and more recent |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Available in |
1.2.1412. New Initializers¶
Parameters, static variables and global constants may be initialized with an object.
<?php
function foo( $a = new A) {
static $static = new B;
}
const A = new C;
?>
This feature is available in PHP 8.1 and more recent. It is reported as an invalid constant expression in older PHP versions.
See also PHP RFC: New in initializers <https://wiki.php.net/rfc/new_in_initializers> and Nested Attributes.
1.2.1412.1. Specs¶
Short name |
Php/NewInitializers |
Rulesets |
Appinfo, CompatibilityPHP73, CompatibilityPHP74, CompatibilityPHP80, All |
Exakat since |
2.3.1 |
PHP Version |
With PHP 8.1 and more recent |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Available in |
1.2.1413. PHP 8.1 Resources Turned Into Objects¶
Multiple PHP native functions now return objects, not resources. Any check on those values with is_resource() is now going to fail.
The affected functions are the following :
ldap_next_entry ()
pg_execute ()
See also UPGRADING PHP 8.1.
1.2.1413.1. Suggestions¶
Change the condition from is_resource() to instanceof
1.2.1413.2. Specs¶
Short name |
Php/Php81RemovesResources |
Rulesets |
none |
Exakat since |
2.2.0 |
PHP Version |
All |
Severity |
Major |
Time To Fix |
Quick (30 mins) |
Precision |
Medium |
Available in |
1.2.1414. version_compare Operator¶
version_compare()’s third argument is checked for value. The third argument specificies the operator, which may be only one of the following : <, lt, <=, le, >, gt, >=, ge, ==, =, eq, !=, <>, ne. The operator is case sensitive.
Until PHP 8.1, it was silently reverted to the default value. It is a deprecated warning in PHP 8.1 and will be finalized in PHP 9.0. It is recommended to fix this parameter in any PHP version.
<?php
// return true
var_dump(version_compare('2.0', '2.1', '<'));
// returns false
var_dump(version_compare('2.0', '2.1', '>'));
// returns NULL and might be interpreted as false
var_dump(version_compare('2.0', '2.1', 'as'));
?>
1.2.1414.1. Suggestions¶
Use a valid comparison operator
1.2.1414.2. Specs¶
Short name |
Php/VersionCompareOperator |
Rulesets |
none |
Exakat since |
2.3.1 |
PHP Version |
With PHP 8.1 and more recent |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1415. Cannot Call Trait Method Directly¶
<?php
trait t { static public function t() {}}
t::t();
a::t();
class a {
use t;
}
?>
See also Calling a `static element on a trait <https://www.php.net/manual/en/migration81.deprecated.php#migration81.deprecated.core.`static <https://www.php.net/manual/en/language.oop5.static.php>`_-trait>`_.
1.2.1415.1. Suggestions¶
Use the trait in a class, and call the method from the class.
1.2.1415.2. Specs¶
Short name |
Traits/CannotCallTraitMethod |
Rulesets |
|
Exakat since |
2.3.1 |
PHP Version |
8.1- |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Unknown |
Available in |
1.2.1416. Deprecated Callable¶
Callables that are supported by call_user_func($callable), but not by $callable() are deprecated.
One important aspect is the loss of context : ‘self::method’ may be created anywhere in the code, while self::class can only be used inside a class, and, in that case, inside the target class.
<?php
class x {
// This will fail
function foo(callable $callable) {
$callable();
}
function method() {
}
}
$x = new x;
$x->foo('self::method');
?>
It is recommended to update the code with any PHP version, to prepare for the future removal of the feature.
1.2.1416.1. Suggestions¶
Replace the keyword (such as self) by the full class name, with self::class.
Use a variable and the $s(…) syntax.
See also and PHP RFC: Deprecate partially supported callables.
1.2.1416.2. Specs¶
Short name |
Functions/DeprecatedCallable |
Rulesets |
|
Exakat since |
2.3.1 |
PHP Version |
8.2- |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1417. Promoted Properties¶
Promoted proprerties is a way to declare the properties within the constructor, and have them assigned to the constructing value at instantiation.
<?php
class CustomerDTO
{
public function __construct(
public string $name,
public string $email,
public DateTimeImmutable $birth_date,
) {}
}
?>
See also Constructor Promotion and PHP 8: Constructor property promotion.
1.2.1418. Overwritten Foreach Var¶
When using standard blind variable names, nested foreach may lead to overwriting the variables.
Careful coding may take advantage of that feature. Though, it tends to be error prone, and will generate bugs if the code is refactored.
<?php
foreach($array as $key => $value) {
foreach($array as $key2 => $value) {
// $value is now the one of the 2nd foreach, not the first.
}
}
?>
1.2.1418.1. Suggestions¶
Change the name of one of the blind variable to use a distinct name
Remove usage of one of the double variable
Remove the nested foreach()
Move the nested foreach() to a method
1.2.1419. Null Type Favorite¶
Null typed may be written in two ways : with ? or with union type and null.
The analyzed code has less than 10% of one of them : for consistency reasons, it is recommended to make them all the same.
<?php
function foo(?A $a) : B|null {
// some code
}
?>
1.2.1419.1. Suggestions¶
1.2.1419.2. Specs¶
Short name |
Functions/NullTypeFavorite |
Rulesets |
|
Exakat since |
2.3.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1420. Checks Property Existence¶
This analysis reports checks on property existence.
In PHP 8.2, non-specified properties are discouraged : they should always be defined in the class code. When this guideline is applied, properties always exists, and a call to property_exists() is now useless.
Some situations are still legit : + When the class is stdclass, where no property is initially defined. This may be the case of JSON data, or arrays cast to objects. + When the class uses magic methods, in particular __get(), __set() and __isset().
<?php
?>
In this analysis, isset() and property_exists() are both used to detect this checking behavior. property_exists() is actually the only method to actually check the existance, since isset() will confuse non-existing properties and null.
While the behavior is deprecated in PHP 8.2, it is recommended to review older code and remove it. It will both ensure forward compability and cleaner, faster local code.
1.2.1420.2. Specs¶
Short name |
Classes/ChecksPropertyExistence |
Rulesets |
|
Exakat since |
2.3.3 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1421. Extends Stdclass¶
Those classes extends stdclass.
Traditionnaly, classes are defined independantly, without any native class extension.
In PHP 8.2, dynamic properties are deprecated, and yield a warning in the logs. Adding ‘extends stdclass’ to classes signature removes this warning, as stdclass is the empty class, without any method, property nor constants.
<?php
class myClass extends \stdClass {
function __set($a, $b) {
$this->$a = $b;
}
}
?>
1.2.1421.2. Specs¶
Short name |
Classes/ExtendsStdclass |
Rulesets |
|
Exakat since |
2.3.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
High |
Available in |
1.2.1422. Variable Typehint¶
Adds typehints to (local) variables, by inference from the code.
Currently, the variable must be assigned only one type within its context to be typed. Non-typed variables limit the scope of other rules.
This is an internal tool, to help find definitions of classes. The same strategies may happen to arguments, though there is no syntax relay for variables.
<?php
function foo() {
$a = 1;
return $a;
}
?>
1.2.1422.1. Suggestions¶
1.2.1423. Scope Resolution Operator¶
The scope resolution operator ::class is faster than a call to get_class() function.
<?php
$a = new stdClass();
echo $a::class;
// identical to
echo get_class($a);
?>
1.2.1423.1. Suggestions¶
use the operator instead of the call to get_class()
See also and get_class..
1.2.1423.2. Specs¶
Short name |
Performances/ClassOperator |
Rulesets |
|
Exakat since |
2.3.3 |
PHP Version |
With PHP 7.0 and more recent |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Very high |
Available in |
1.2.1424. Could Use Nullable Object Operator¶
When the previous call may end up as null, the null-safe object operator will prevent fatal errors.
<?php
// direct, uncertain usage
foo()->b();
$a = foo();
$c = $a ? $a->b() : null;
function foo() : ?A {
return new A();
}
class A {
function b() : string { return '';}
}
?>
1.2.1424.1. Suggestions¶
Add a test before using the return value
Update the previous method to prevent it from returning null
Use the null-safe object operator
See also PHP 8.0 feature focus: nullsafe methods and Nullsafe methods and properties.
1.2.1424.2. Specs¶
Short name |
Structures/CouldUseNullableOperator |
Rulesets |
|
Exakat since |
2.3.3 |
PHP Version |
With PHP 8.0 and more recent |
Severity |
Major |
Time To Fix |
Slow (1 hour) |
Precision |
Medium |
Available in |
1.2.1425. Cant Overload Constants¶
It was not possible to overload class constants within a class, when the constant was defined in an interface.
<?php
interface i {
const A = 1;
}
//This lints, but doesn't executin in PHP 8.0 and older.
class x implements i {
const A = 1;
}
?>
1.2.1425.1. Suggestions¶
Avoid overloading constants
Define the constants only in the classes
See also and interface constants <https://www.php.net/manual/en/language.oop5.interfaces.php#language.oop5.interfaces.constants>.
1.2.1425.2. Specs¶
Short name |
Interfaces/CantOverloadConstants |
Rulesets |
CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, CompatibilityPHP70, CompatibilityPHP71, CompatibilityPHP72, CompatibilityPHP73, CompatibilityPHP74, CompatibilityPHP80, LintButWontExec, All |
Exakat since |
2.3.2 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Unknown |
Available in |
1.2.1426. Variable Is A Local Constant¶
A variable that is written once, then never modified, just like a constant.
<?php
function foo() {
$localConstant = 'Hello';
echo $localConstant;
$variable = 'Hello, ';
$variable .= date('r');
echo $variable;
}
?>
1.2.1427. Classes/CouldBeIterable¶
1.2.1427.1. Suggestions¶
1.2.1427.2. Specs¶
Short name |
Classes/CouldBeIterable |
Rulesets |
|
Exakat since |
2.3.3 |
PHP Version |
8.0+ |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Unknown |
Available in |
1.2.1428. Intersection Typehint¶
Intersection typehints allows the combinaison of several typehint for the same argument or return value.
Several typehints are specified at the same place as a single one. The different values are separated by a ampersand character &.
<?php
class Number {
private A&B $object;
}
?>
Intersection types are a PHP 8.1 new feature. See also PHP RFC: Pure intersection types, Type declarations and How the New Intersection Types in PHP 8.1 Give You More Flexibility.
1.2.1429. Abstract Class Constants¶
Those are class constants which are defined in multiple children, but not in the parent class.
If this class is a feature of the parent class, or shall and must be defined in the children classes, it is recommended to add them in the parent class, and let them overloaded in the children class.
In the illustration below, CONSTA is defined in all two children, but not in the parent class. A third children would miss the constants definitions, until an error has been reported.
<?php
class A {
// no constant
}
class A1 extends A {
public const CONSTA = 1;
}
class A2 extends A {
public const CONSTA = 2;
}
?>
1.2.1429.1. Suggestions¶
Define the constants in the parent class, with some neutral value
Name |
Default |
Type |
Description |
minimum |
2 |
integer |
Minimal number of constant found in children to report this as a potential abstract class. |
See also and I often find myself wishing for abstract constants in PHP.
1.2.1429.2. Specs¶
Short name |
Classes/AbstractConstants |
Rulesets |
|
Exakat since |
2.3.3 |
PHP Version |
All |
Severity |
Minor |
Time To Fix |
Quick (30 mins) |
Precision |
Unknown |
Available in |
1.2.1430. Recycled Variables¶
A recycled variable is used for two distinct missions in a method. There is usually a first
<?php
function foo() {
$variable = initial; // first initialisation
$variable = goo($variable); // processing the variable
hoo($variable); // sending the variable to a final destination
$variable = second ; // second initialisation
hoo2($variable); // sending the variable to a different final destination
}
?>
1.2.1431. Getter And Setter¶
A getter is a method whose purpose is to read the internal value of a class; a setter is a method whose purpose is to write a value inside a classe.
Exakat marks simple setters and getters : their content only writes (resp. reads) on property at a time. More refined getters/setters might appear in the future, when formatting and filter is detected and omitted.
<?php
class x {
private $p = 1;
// getter
function getP() {
return $this->p;
}
// setter
function setP($a) {
$this->p = $a;
}
}
?>
1.2.1432. Check Division By Zero¶
Always check before dividing by a value. If that value is cast to 0, PHP might stop the processing with an exception, or keep processing it with 0 as a result. Both will raise problems.
The best practise is to check the incoming value before attempting the division. On possible alternative is to catch the DivisionByZero exception, that PHP 8.0 and more recent will raise. .. code-block:: php
<?php
// Check the value before usage function foo($a = 1) {
- if ($a !== 0) {
return 42 / $a;
- } else {
// process an error
}
}
// Check the value after usage (worse than the above) function foo($a = 1) {
- try {
return 42 / $a;
- } catch (DivisionByZero) {
// fix the situation now
}
}
// This might fails with a division by 0 function foo($a = 1) {
return 42 / $a;
}
?>
1.3. Directory by Exakat version¶
List of analyzers, by version of introduction, newest to oldest. In parenthesis, the first element is the analyzer name, used with ‘analyze -P’ command, and the seconds, if any, are the ruleset, used with the -T option. Rulesets are separated by commas, as the same analysis may be used in several rulesets.
2.3.3
2.3.2
2.3.1
2.3.0
2.2.5
2.2.4
2.2.3
2.2.2
2.2.1
2.2.0
2.1.9
Complete/PhpExtStubPropertyMethod
2.1.8
2.1.7
2.1.6
2.1.5
2.1.4
2.1.3
2.1.2
2.1.1
2.1.0
2.0.9
2.0.8
2.0.7
2.0.6
2.0.5
2.0.4
2.0.3
2.0.2
1.9.9
Complete/CreateForeachDefault
1.9.8
1.9.7
1.9.6
1.9.5
1.9.4
1.9.3
Complete/SetClassRemoteDefinitionWithParenthesis
Complete/SetClassRemoteDefinitionWithTypehint
Environment Variables
1.9.2
Complete/SetClassRemoteDefinitionWithInjection
1.9.1
Complete/PhpNativeReference
1.9.0
1.8.9
1.8.8
1.8.7
1.8.6
1.8.5
1.8.4
1.8.3
1.8.2
1.8.1
1.8.0
1.7.9
1.7.8
1.7.7
1.7.6
1.7.2
1.7.0
1.6.9
1.6.8
1.6.7
1.6.6
1.6.5
1.6.4
1.6.3
1.6.2
1.6.1
1.5.8
1.5.7
1.5.6
1.5.5
1.5.4
1.5.3
1.5.2
1.5.1
1.5.0
1.4.9
1.4.8
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.9
1.3.8
1.3.7
1.3.5
1.3.4
1.3.3
1.3.2
1.3.0
1.2.9
1.2.8
1.2.7
1.2.6
1.2.5
1.2.4
1.2.3
1.2.2
1.2.1
1.1.10
1.1.9
1.1.8
1.1.7
1.1.6
1.1.5
1.1.4
1.1.3
1.1.2
1.1.1
1.0.11
1.0.10
1.0.8
1.0.7
1.0.6
1.0.5
Environment Variables
1.0.4
1.0.3
1.0.1
0.12.17
0.12.16
0.12.15
0.12.14
0.12.12
0.12.11
0.12.10
0.12.9
0.12.8
0.12.7
0.12.5
0.12.4
0.12.3
0.12.2
0.12.1
0.12.0
0.11.8
0.11.7
0.11.6
0.11.5
0.11.4
0.11.3
0.11.2
0.11.1
0.11.0
0.10.9
0.10.7
0.10.6
0.10.5
0.10.4
0.10.3
0.10.2
0.10.1
0.10.0
0.9.9
0.9.8
0.9.7
0.9.6
0.9.5
0.9.4
0.9.3
0.9.2
0.9.1
0.9.0
0.8.9
0.8.7
0.8.6
0.8.5
0.8.4
Inclusions
0.8.3
1.4. Directory by PHP Function¶
- ` `
` xmlwriter_open_memory()`
- $
$HTTP_RAW_POST_DATA
$_ENV
$_GET
$_POST
$_REQUEST
$this
- .
…
- A
AF_INET
ArrayAccess
ArrayIterator
ArrayObject
Array_search()
abs()
addslashes()
array()
array_change_key_case()
array_chunk()
array_column()
array_count_values()
array_diff()
array_diff_assoc()
array_diff_key()
array_diff_uassoc()
array_fill()
array_fill_keys()
array_filter()
array_flip()
array_intersect()
array_key_exists()
array_keys()
array_map()
array_merge()
array_merge_recursive()
array_multisort()
array_pad()
array_product()
array_push()
array_replace()
array_search()
array_shift()
array_slice()
array_splice()
array_sum()
array_udiff()
array_uintersect()
array_unique()
array_unshift()
array_values()
array_walk()
arrayaccess
arrayobject
arsort()
asort()
assert()
- B
Break
basename()
break
- C
CAL_GREGORIAN
COM
COUNT_NORMAL
COUNT_RECURSIVE
CURLOPT_FILE
CURLOPT_HEADER
CURLOPT_SSL_VERIFYPEER
CURLOPT_URL
CURLPIPE_HTTP1
CURLVERSION_NOW
Cairo
CairoContext
CairoPSSurface
Closure
Collator
Compact()
Concurrent Task
Count()
Countable
cairo
call_user_func()
call_user_method()
call_user_method_array()
ceil()
chdir()
chmod()
chr()
chroot()
class_alias()
class_exists()
closure
collator_compare()
collator_get_sort_key()
com
php-cs-fixable
compact()
constant()
continue
convert_cyr_string()
copy()
count()
countable
crc32()
create_function()
crypt()
curl_exec()
curl_init()
curl_multi_errno()
curl_multi_init()
curl_setopt()
curl_share_errno()
curl_share_init()
curl_share_strerror()
curl_version()
curlopt_ssl_verifypeer
current()
- D
DB2_AUTOCOMMIT_OFF
DIRECTORY_SEPARATOR
DNS_NS
DOMDocument
DateInterval
DateTime
DateTimeImmutable
DateTimeZone
Datetime
Define()
Die
Die()
Directory
DirectoryIterator
DivisionByZeroError
date()
dateTime
date_create()
datetime
datetimeimmutable
debug_backtrace()
debug_zval_dump()
define()
die
die()
directory
dirname()
dl()
- E
ENT_COMPAT
ENT_IGNORE
ENT_QUOTES
EV_PERSIST
EV_READ
EXTR_OVERWRITE
EXTR_PREFIX_ALL
EXTR_SKIP
E_ALL
E_DEPRECATED
E_ERROR
E_NOTICE
E_PARSE
E_STRICT
E_USER_ERROR
E_USER_NOTICE
E_USER_WARNING
E_WARNING
Each()
Exit
each()
easter_days()
eio_event_loop()
empty()
enchant_broker_init()
enchant_broker_request_dict()
enchant_broker_request_pwl_dict()
ereg()
ereg_replace()
eregi()
eregi_replace()
error_clear_last()
error_get_last()
error_log()
error_reporting()
eval()
event_base_new()
event_new()
exec()
exit
exit()
explode()
extract()
ezmlm_hash()
- F
FANN_SIGMOID_SYMMETRIC
FILEINFO_MIME_TYPE
FILE_BINARY
FILE_IGNORE_NEW_LINES
FILE_TEXT
FILTER_SANITIZE_EMAIL
FILTER_SANITIZE_MAGIC_QUOTES
FILTER_SANITIZE_SPECIAL_CHARS
FILTER_SANITIZE_STRING
FILTER_UNSAFE_RAW
FILTER_VALIDATE_EMAIL
FTP_BINARY
FilesystemIterator
For()
Foreach()
fdf_create()
feof()
fgetc()
fgetcsv()
fgets()
fgetss()
file()
file_exists()
file_get_contents()
file_put_contents()
filesize()
filter_input()
filter_input_array()
filter_var()
finfo_open()
floor()
fopen()
for()
foreach()
forward_static_call()
forward_static_call_array()
fputcsv()
fread()
fscanf()
fseek()
ftp_connect()
func_get_arg()
func_get_args()
func_num_args()
- G
GLOB_BRACE
GLOB_NOSORT
GNUPG_SIG_MODE_CLEAR
Generator
GnuPG
gc_mem_caches()
generator
getType()
get_browser()
get_called_class()
get_class()
get_html_translation_table()
get_magic_quotes_gpc()
get_magic_quotes_gpc_runtime()
get_magic_quotes_runtime()
get_object_vars()
getenv()
gettext()
glob()
gmp_div_q()
gmp_div_qr()
gmp_div_r()
gmp_random()
gnupg
gnupg_init()
gzgetss()
- H
HTML_ENTITIES
hash()
hash_algos()
hash_equals()
hash_file()
hash_hmac()
hash_update()
hash_update_file()
header()
hebrevc()
highlight_file()
highlight_string()
html_entity_decode()
htmlentities()
htmlspecialchars()
htmlspecialchars_decode()
http_build_query()
http_build_url()
http_parse_cookie()
http_parse_params()
http_redirect()
http_support()
- I
INF
INTL_IDNA_VARIANT_2003
INTL_IDNA_VARIANT_UTS46
IN_ATTRIB
Intval()
Isset
ibase_errmsg()
iconv()
iconv_strpos()
iconv_strrpos()
idn_to_ascii()
idn_to_utf8()
image2wbmp()
imagecolorallocate()
imagecolorallocatealpha()
imagepsbbox()
imagepsencodefont()
imagepsextendfont()
imagepsfreefont()
imagepsloadfont()
imagepsslantfont()
imagepstext()
imap_last_error()
imap_open()
implode()
import_request_variables()
in_array()
ini_get()
ini_set()
inotify_init()
inotify_queue_len()
inotify_read()
instanceof
insteadof
intdiv()
intl_idna_variant_2003
intval()
is_a()
is_array()
is_callable()
is_int()
is_integer()
is_iterable()
is_null()
is_object()
is_real()
is_resource()
is_scalar()
is_string()
isset
iterator_to_array()
- J
JSON_ERROR_NONE
JSON_HEX_AMP
Judy
jdtojewish()
jpeg2wbmp()
json_decode()
json_last_error()
judy
- K
KADM5_PRINC_EXPIRE_TIME
key()
krsort()
ksort()
- L
LC_ALL
LC_MESSAGES
LIBXML_DTDLOAD
LIBXML_ERR_ERROR
LIBXML_ERR_FATAL
LIBXML_ERR_WARNING
LIBXML_NOENT
LOG_DEBUG
List()
Locale
LogicException
ldap_connect()
ldap_first_entry()
ldap_list()
ldap_read()
ldap_search()
ldap_sort()
libxml_clear_errors()
libxml_get_errors()
link()
list()
locale
log()
ltrim()
- M
MATch()
MAtch()
MB_OVERLOAD_MAIL
MB_OVERLOAD_REGEX
MB_OVERLOAD_STRING
MCRYPT_CAST_256
MCRYPT_DEV_RANDOM
MCRYPT_MODE_CBC
MCRYPT_MODE_CFB
MCRYPT_RAND
MCRYPT_RIJNDAEL_128
MHASH_MD5
MYSQLI
MYSQLI_STMT_ATTR_UPDATE_MAX_LENGTH
MYSQLI_STORE_RESULT_COPY_DATA
M_PI
Match()
Memcache
MessageFormatter
MessagePack
Mongo
MongoClient
MongoDB
MongoDb
Mongodb
MySQLI
MySQLi
magic_quotes_runtime()
mail()
mailparse_msg_create()
match()
mb_chr()
mb_encoding_aliases()
mb_list_encodings()
mb_ord()
mb_scrub()
mb_split()
mb_stripos()
mb_stristr()
mb_strlen()
mb_strpos()
mb_strrchr()
mb_strrichr()
mb_strripos()
mb_strrpos()
mb_strstr()
mb_substr()
mbereg()
mbereg_match()
mbereg_replace()
mbereg_search()
mbereg_search_getpos()
mbereg_search_getregs()
mbereg_search_init()
mbereg_search_pos()
mbereg_search_regs()
mbereg_search_setpos()
mberegi()
mberegi_replace()
mbregex_encoding()
mbsplit()
mcrypt_cbc()
mcrypt_cfb()
mcrypt_decrypt
mcrypt_ecb()
mcrypt_encrypt
mcrypt_get_iv_size()
mcrypt_ofb()
md5()
md5_file()
memcache
microtime()
mkdir()
money_format()
mongo
mongodb
move_uploaded_file()
msg_get_queue()
mt_rand()
mt_srand()
mysql_error()
mysqli
mysqli_connect_errno()
mysqli_connect_error()
- N
NCURSES_COLOR_BLACK
NCURSES_COLOR_GREEN
NCURSES_COLOR_RED
NCURSES_COLOR_WHITE
NULL
Null
NumberFormatter
ncurses_init()
ncurses_start_color()
next()
nl2br()
null
- O
OCI_ASSOC
OCI_RETURN_NULLS
OPENSSL_CIPHER_AES_128_CBC
OPENSSL_CIPHER_RC2_40
OPENSSL_KEYTYPE_DH
OPENSSL_KEYTYPE_DSA
OPENSSL_KEYTYPE_EC
OPENSSL_KEYTYPE_RSA
OP_HALFOPEN
O_NOCTTY
O_NONBLOCK
O_RDWR
ob_end_flush()
ob_get_clean()
ob_start()
oci_error()
opcache_get_status()
opencensus_trace_finish()
opencensus_trace_list()
opendir()
openssl_csr_new()
openssl_csr_sign()
openssl_encrypt()
openssl_get_cipher_methods()
openssl_pkcs7_encrypt()
openssl_pkey_new()
openssl_random_pseudo_bytes()
openssl_x509_read()
- P
PARENT
PARSEKIT_SIMPLE
PASSWORD_ARGON2I
PASSWORD_ARGON2_DEFAULT_THREADS
PASSWORD_ARGON2_DEFAULT_TIME_COST
PASSWORD_DEFAULT
PATHINFO_BASENAME
PATHINFO_DIRNAME
PHP_INT_MAX
PREG_SET_ORDER
PREG_SPLIT_NO_EMPTY
PREG_UNMATCHED_AS_NULL
Parent
ParseError
pack()
Inventory
parent
parse_ini_file()
parse_ini_string()
parse_str()
parse_url()
parsekit_compile_file()
parsekit_compile_string()
passthru()
password_hash()
password_verify()
pathinfo()
pcntl_fork()
pcntl_getpriority()
pg_connect()
pg_lo_create()
pg_pconnect()
pg_query()
pg_result_status()
pg_select()
php_egg_logo_guid()
php_logo_guid()
php_real_logo_guid()
php_sapi_name()
phpcredits()
phpinfo()
phpversion()
pi()
png2wbmp()
posix_access()
posix_get_last_error()
posix_setsid()
pow()
preg_filter()
preg_grep()
preg_last_error_msg()
preg_match()
preg_match_all()
preg_replace()
preg_replace_callback()
preg_replace_callback_array()
preg_split()
prev()
printf()
proc_nice()
proc_open()
property_exists()
pspell_config_create()
pspell_new()
pspell_new_config()
pspell_new_personal()
putenv()
- R
RDkafka
RUNKIT_ACC_PUBLIC
RarArchive
RdKafka
RecursiveFilterIterator
RuntimeException
rand()
random_bytes()
random_int()
rdkafka
read_exif_data()
readdir()
readfile()
readline_info()
recode()
recode_file()
recode_string()
register_shutdown_function()
register_tick_function()
restore_include_path()
round()
rsort()
rtrim()
runkit_import()
- S
SCANDIR_SORT_NONE
SDL_GetError()
SDL_INIT_VIDEO
SDL_Quit()
SELF
SIGHUP
SIGKILL
SIGTERM
SNMP
SOAP_1_2
SOCK_STREAM
SOL_TCP
SORT_LOCALE_STRING
SORT_NUMERIC
SORT_REGULAR
SORT_STRING
SWFAction
SWFMovie
SWFShape
SWFSprite
SeasLog
Seaslog
Self
SimpleXMLElement
SoapClient
SplFileObject
SplQueue
SplTempFileObject
Static
StdClass
Stdclass
Strtr()
Substr()
Switch()
scandir()
seaslog
self
sem_get()
session_start()
set_error_handler()
set_exception_handler()
set_magic_quotes_runtime()
set_socket_blocking()
setcookie()
setlocale()
setrawcookie()
settype()
sha1()
sha1_file()
shell_exec()
Preferences
shm_attach()
shmop_open()
show_source()
simplexml_load_file()
simplexml_load_string()
sizeof()
sleep()
snmp
socket_accept()
socket_addrinfo_bind()
socket_addrinfo_connect()
socket_connect()
socket_create()
socket_create_listen()
socket_import_stream()
socket_last_error()
socket_read()
socket_wsaprotocol_info_import()
sort()
spl_autoload_register()
split()
spliti()
sprintf()
sql_regcase()
sqlsrv_errors()
srand()
static
Coding conventions
stdClass
stdclass
str_ireplace()
str_pad()
str_repeat()
str_replace()
stream_isatty()
stream_select()
stream_set_blocking()
stream_socket_client()
stream_socket_server()
strip_tags()
stripos()
strlen()
strpos()
strripos()
strrpos()
strstr()
strtok()
strtolower()
strtotime()
strtoupper()
strtr()
strval()
substr()
substr_replace()
switch()
sys_get_temp_dir()
system()
- T
T_COMMENT
T_DOC_COMMENT
Throwable
Tidy
Traversable
throwable
tidy
time()
token_get_all()
track_errors
traversable
trigger_error()
trim()
- U
Unset()
Usort()
uasort()
uksort()
uniqid()
unpack()
unserialize()
unset()
urlencode()
usleep()
usort()
uuid_create()
- V
var_dump()
var_export()
version_compare()
vprintf()
- W
WeakReference
while()
wordwrap()
- X
XHPROF_FLAGS_CPU
XHPROF_FLAGS_MEMORY
XSLTProcessor
xdebug_call_class()
xdebug_call_file()
xdebug_call_function()
xdebug_call_line()
xhprof_disable()
xml_parser_create()
xml_parser_create_ns()
- Y
yaml_parse()
yaml_parse_file()
- Z
ZipArchive
ZooKeeper
Zookeeper
ZookeeperException
zend_logo_guid()
zookeeper
- _
_()
__CLASS__
__DIR__
__FILE__
__FUNCTION__
__LINE__
__METHOD__
__call
__callStatic
__clone
__construct
__debugInfo
__destruct
__get
__invoke
__isset
__set
__set_state
__sleep
__toString
__tostring
__unset
__wakeup
1.5. Directory by PHP Features¶
$this
Array
Array With Curly Braces
Arrays
Attributes
Binary Integer
Class Constants Visibility
Class constant
Classes
Comparison
Constant Scalar Expression
Constants
Contravariance
Cookie
Countable interface
Covariance
Disable classes
Dynamic Properties
Exponent
Final Class Constants
Final Keyword
First Class Callable
Foreach
Function Subscripting
Functions
GLOBALS, the variable
Global Variables
Hash
Inclusions
Inclusions
Inclusions
Indentation
Inheritance
Interfaces
Interpolation
Intersection Type
Loops
Magic Constants
Magic Methods
Match
Method
Mixed return type
Named Parameters
Namespaces
Nested Attributes
Never return type
New In Initializers
Null
Null Safe Object Operator
Nullable
Operators
Promoted Properties
Properties
Property Type Declaration
Random
Regular Expressions
Return Type Will Change
Scope Resolution Operator
Static Method
Static Variables
String
Stringable
Superglobal variables
Switch
Traits
Try-catch
Typehint
Union type
Validation
Var
Variable Variables
Variables
Visibility
constructor
disable functions
integer
isset
pack
parent
phpinfo()
self
static
stdclass
throw
1.6. Directory by PHP Error message¶
Exakat helps reduce the amount of error and warning that code is producing by reporting pattern that are likely to emit errors.
186 PHP error message detailled :
“continue” targeting switch is equivalent to “break”. Did you mean to use “continue 2”?
$GLOBALS can only be modified using the $GLOBALS[$name] = $value syntax
A function with return type must return a value (did you mean “return null;” instead of “return;”?)
Access level to Bar::$publicProperty must be public (as in class Foo)
Access level to c::iPrivate() must be public (as in class i)
An alias (%s) was defined for method %s(), but this method does not exist
Argument 1 passed to foo() must be of the type integer, string given
Array and string offset access syntax with curly braces is deprecated
Attribute “AttributeFunction” cannot target Class (allowed targets: Function)
Calling static trait method t::t is deprecated, it should only be called on a class using the trait
Cannot access parent:: when current class scope has no parent
Cannot access parent:: when current class scope has no parent
Cannot access parent:: when current class scope has no parent
Cannot inherit previously-inherited or override constant A from interface
Cannot inherit previously-inherited or override constant A from interface i
Cannot use int as default value for parameter $a of type string
Cannot use int as default value for property x::$a of type string
Cannot use isset() on the result of an expression (you can use “null !== expression” instead)
Case-insensitive constants are deprecated. The correct casing for this constant is “A”
Class fooThrowable cannot implement interface Throwable, extend Exception or Error instead
Class x must implement interface Traversable as part of either Iterator or IteratorAggregate
Declaration of FooParent::Bar() must be compatible with FooChildren::Bar()
Declaration of a::foo($a) should be compatible with ab1::foo($a)
Declaration of ab::foo($a) must be compatible with a::foo($a = 1)
Declaration of ab::foo($a) must be compatible with a::foo($a = 1)
Declaration of ab::foo($a) should be compatible with a::foo($a = 1)
Declaration of ab::foo($a) should be compatible with a::foo($a = 1)
Default value for parameters with a int type can only be int or NULL
Defining a custom assert() function is deprecated, as the function has special semantics
Deprecated: Required parameter $y follows optional parameter $x
Implicit conversion from float 3.141592653589793 to int loses precision
Indirect modification of overloaded property c::$b has no effect
Passing null to parameter #2 ($offset) of type int is deprecated
Private constant MyClass::Z cannot be final as it is not visible to other classes
Private methods cannot be final as they are never overridden by other classes
Return value of foo() must be an instance of Bar, none returned
Return value of foo() must be of the type int, string returned
The behavior of unparenthesized expressions containing both ‘.’ and ‘>>’/’
The each() function is deprecated. This message will be suppressed on further calls
The parent constructor was not called: the object is in an invalid state
Too few arguments to function foo(), 1 passed and exactly 2 expected
Too few arguments to function foo(), 1 passed and exactly 2 expected
Trait method M has not been applied, because there are collisions with other trait methods on C
Trait method f has not been applied, because there are collisions with other trait methods on x
Uncaught ArgumentCountError: Too few arguments to function, 0 passed
Uncaught TypeError: Cannot auto-initialize an array inside property x::$P of type bool
Use of undefined constant y - assumed ‘y’ (this will throw an Error in a future version of PHP)
Using array_key_exists() on objects is deprecated. Use isset() or property_exists() instead
__autoload() is deprecated, use spl_autoload_register() instead
define(): Declaration of case-insensitive constants is deprecated
iconv(): Wrong charset, conversion from UTF-8’ to ASCII//TRANSLIT’ is not allowed
include(a.php): failed to open stream: No such file or directory
syntax error, unexpected ‘&’, expecting variable (T_VARIABLE)
syntax error, unexpected ‘|’, expecting variable (T_VARIABLE)
version_compare(): Argument #3 ($operator) must be a valid comparison operator